Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1901 | serge | 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(&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 | GLenum target, |
||
97 | GLintptrARB offset, |
||
98 | GLsizeiptrARB size, |
||
99 | const GLvoid * data, struct gl_buffer_object *obj) |
||
100 | { |
||
101 | struct st_buffer_object *st_obj = st_buffer_object(obj); |
||
102 | |||
103 | /* we may be called from VBO code, so double-check params here */ |
||
104 | ASSERT(offset >= 0); |
||
105 | ASSERT(size >= 0); |
||
106 | ASSERT(offset + size <= obj->Size); |
||
107 | |||
108 | if (!size) |
||
109 | return; |
||
110 | |||
111 | /* |
||
112 | * According to ARB_vertex_buffer_object specification, if data is null, |
||
113 | * then the contents of the buffer object's data store is undefined. We just |
||
114 | * ignore, and leave it unchanged. |
||
115 | */ |
||
116 | if (!data) |
||
117 | return; |
||
118 | |||
119 | /* Now that transfers are per-context, we don't have to figure out |
||
120 | * flushing here. Usually drivers won't need to flush in this case |
||
121 | * even if the buffer is currently referenced by hardware - they |
||
122 | * just queue the upload as dma rather than mapping the underlying |
||
123 | * buffer directly. |
||
124 | */ |
||
125 | pipe_buffer_write(st_context(ctx)->pipe, |
||
126 | st_obj->buffer, |
||
127 | offset, size, data); |
||
128 | } |
||
129 | |||
130 | |||
131 | /** |
||
132 | * Called via glGetBufferSubDataARB(). |
||
133 | */ |
||
134 | static void |
||
135 | st_bufferobj_get_subdata(struct gl_context *ctx, |
||
136 | GLenum target, |
||
137 | GLintptrARB offset, |
||
138 | GLsizeiptrARB size, |
||
139 | GLvoid * data, struct gl_buffer_object *obj) |
||
140 | { |
||
141 | struct st_buffer_object *st_obj = st_buffer_object(obj); |
||
142 | |||
143 | /* we may be called from VBO code, so double-check params here */ |
||
144 | ASSERT(offset >= 0); |
||
145 | ASSERT(size >= 0); |
||
146 | ASSERT(offset + size <= obj->Size); |
||
147 | |||
148 | if (!size) |
||
149 | return; |
||
150 | |||
151 | pipe_buffer_read(st_context(ctx)->pipe, st_obj->buffer, |
||
152 | offset, size, data); |
||
153 | } |
||
154 | |||
155 | |||
156 | /** |
||
157 | * Allocate space for and store data in a buffer object. Any data that was |
||
158 | * previously stored in the buffer object is lost. If data is NULL, |
||
159 | * memory will be allocated, but no copy will occur. |
||
160 | * Called via ctx->Driver.BufferData(). |
||
161 | * \return GL_TRUE for success, GL_FALSE if out of memory |
||
162 | */ |
||
163 | static GLboolean |
||
164 | st_bufferobj_data(struct gl_context *ctx, |
||
165 | GLenum target, |
||
166 | GLsizeiptrARB size, |
||
167 | const GLvoid * data, |
||
168 | GLenum usage, |
||
169 | struct gl_buffer_object *obj) |
||
170 | { |
||
171 | struct st_context *st = st_context(ctx); |
||
172 | struct pipe_context *pipe = st->pipe; |
||
173 | struct st_buffer_object *st_obj = st_buffer_object(obj); |
||
174 | unsigned buffer_usage; |
||
175 | |||
176 | st_obj->Base.Size = size; |
||
177 | st_obj->Base.Usage = usage; |
||
178 | |||
179 | switch(target) { |
||
180 | case GL_PIXEL_PACK_BUFFER_ARB: |
||
181 | case GL_PIXEL_UNPACK_BUFFER_ARB: |
||
182 | buffer_usage = PIPE_BIND_RENDER_TARGET; |
||
183 | break; |
||
184 | case GL_ARRAY_BUFFER_ARB: |
||
185 | buffer_usage = PIPE_BIND_VERTEX_BUFFER; |
||
186 | break; |
||
187 | case GL_ELEMENT_ARRAY_BUFFER_ARB: |
||
188 | buffer_usage = PIPE_BIND_INDEX_BUFFER; |
||
189 | break; |
||
190 | default: |
||
191 | buffer_usage = 0; |
||
192 | } |
||
193 | |||
194 | pipe_resource_reference( &st_obj->buffer, NULL ); |
||
195 | |||
196 | if (size != 0) { |
||
197 | st_obj->buffer = pipe_buffer_create(pipe->screen, buffer_usage, size); |
||
198 | |||
199 | if (!st_obj->buffer) { |
||
200 | return GL_FALSE; |
||
201 | } |
||
202 | |||
203 | if (data) |
||
204 | pipe_buffer_write(st_context(ctx)->pipe, st_obj->buffer, 0, |
||
205 | size, data); |
||
206 | return GL_TRUE; |
||
207 | } |
||
208 | |||
209 | return GL_TRUE; |
||
210 | } |
||
211 | |||
212 | |||
213 | /** |
||
214 | * Dummy data whose's pointer is used for zero size buffers or ranges. |
||
215 | */ |
||
216 | static long st_bufferobj_zero_length = 0; |
||
217 | |||
218 | |||
219 | |||
220 | /** |
||
221 | * Called via glMapBufferARB(). |
||
222 | */ |
||
223 | static void * |
||
224 | st_bufferobj_map(struct gl_context *ctx, GLenum target, GLenum access, |
||
225 | struct gl_buffer_object *obj) |
||
226 | { |
||
227 | struct st_buffer_object *st_obj = st_buffer_object(obj); |
||
228 | uint flags; |
||
229 | |||
230 | switch (access) { |
||
231 | case GL_WRITE_ONLY: |
||
232 | flags = PIPE_TRANSFER_WRITE; |
||
233 | break; |
||
234 | case GL_READ_ONLY: |
||
235 | flags = PIPE_TRANSFER_READ; |
||
236 | break; |
||
237 | case GL_READ_WRITE: |
||
238 | default: |
||
239 | flags = PIPE_TRANSFER_READ_WRITE; |
||
240 | break; |
||
241 | } |
||
242 | |||
243 | /* Handle zero-size buffers here rather than in drivers */ |
||
244 | if (obj->Size == 0) { |
||
245 | obj->Pointer = &st_bufferobj_zero_length; |
||
246 | } |
||
247 | else { |
||
248 | obj->Pointer = pipe_buffer_map(st_context(ctx)->pipe, |
||
249 | st_obj->buffer, |
||
250 | flags, |
||
251 | &st_obj->transfer); |
||
252 | } |
||
253 | |||
254 | if (obj->Pointer) { |
||
255 | obj->Offset = 0; |
||
256 | obj->Length = obj->Size; |
||
257 | } |
||
258 | return obj->Pointer; |
||
259 | } |
||
260 | |||
261 | |||
262 | /** |
||
263 | * Called via glMapBufferRange(). |
||
264 | */ |
||
265 | static void * |
||
266 | st_bufferobj_map_range(struct gl_context *ctx, GLenum target, |
||
267 | GLintptr offset, GLsizeiptr length, GLbitfield access, |
||
268 | struct gl_buffer_object *obj) |
||
269 | { |
||
270 | struct pipe_context *pipe = st_context(ctx)->pipe; |
||
271 | struct st_buffer_object *st_obj = st_buffer_object(obj); |
||
272 | enum pipe_transfer_usage flags = 0x0; |
||
273 | |||
274 | if (access & GL_MAP_WRITE_BIT) |
||
275 | flags |= PIPE_TRANSFER_WRITE; |
||
276 | |||
277 | if (access & GL_MAP_READ_BIT) |
||
278 | flags |= PIPE_TRANSFER_READ; |
||
279 | |||
280 | if (access & GL_MAP_FLUSH_EXPLICIT_BIT) |
||
281 | flags |= PIPE_TRANSFER_FLUSH_EXPLICIT; |
||
282 | |||
283 | if (access & GL_MAP_INVALIDATE_RANGE_BIT) |
||
284 | flags |= PIPE_TRANSFER_DISCARD; |
||
285 | |||
286 | if (access & GL_MAP_INVALIDATE_BUFFER_BIT) |
||
287 | flags |= PIPE_TRANSFER_DISCARD; |
||
288 | |||
289 | if (access & GL_MAP_UNSYNCHRONIZED_BIT) |
||
290 | flags |= PIPE_TRANSFER_UNSYNCHRONIZED; |
||
291 | |||
292 | /* ... other flags ... |
||
293 | */ |
||
294 | |||
295 | if (access & MESA_MAP_NOWAIT_BIT) |
||
296 | flags |= PIPE_TRANSFER_DONTBLOCK; |
||
297 | |||
298 | assert(offset >= 0); |
||
299 | assert(length >= 0); |
||
300 | assert(offset < obj->Size); |
||
301 | assert(offset + length <= obj->Size); |
||
302 | |||
303 | /* |
||
304 | * We go out of way here to hide the degenerate yet valid case of zero |
||
305 | * length range from the pipe driver. |
||
306 | */ |
||
307 | if (!length) { |
||
308 | obj->Pointer = &st_bufferobj_zero_length; |
||
309 | } |
||
310 | else { |
||
311 | obj->Pointer = pipe_buffer_map_range(pipe, |
||
312 | st_obj->buffer, |
||
313 | offset, length, |
||
314 | flags, |
||
315 | &st_obj->transfer); |
||
316 | if (obj->Pointer) { |
||
317 | obj->Pointer = (ubyte *) obj->Pointer + offset; |
||
318 | } |
||
319 | } |
||
320 | |||
321 | if (obj->Pointer) { |
||
322 | obj->Offset = offset; |
||
323 | obj->Length = length; |
||
324 | obj->AccessFlags = access; |
||
325 | } |
||
326 | |||
327 | return obj->Pointer; |
||
328 | } |
||
329 | |||
330 | |||
331 | static void |
||
332 | st_bufferobj_flush_mapped_range(struct gl_context *ctx, GLenum target, |
||
333 | GLintptr offset, GLsizeiptr length, |
||
334 | struct gl_buffer_object *obj) |
||
335 | { |
||
336 | struct pipe_context *pipe = st_context(ctx)->pipe; |
||
337 | struct st_buffer_object *st_obj = st_buffer_object(obj); |
||
338 | |||
339 | /* Subrange is relative to mapped range */ |
||
340 | assert(offset >= 0); |
||
341 | assert(length >= 0); |
||
342 | assert(offset + length <= obj->Length); |
||
343 | assert(obj->Pointer); |
||
344 | |||
345 | if (!length) |
||
346 | return; |
||
347 | |||
348 | pipe_buffer_flush_mapped_range(pipe, st_obj->transfer, |
||
349 | obj->Offset + offset, length); |
||
350 | } |
||
351 | |||
352 | |||
353 | /** |
||
354 | * Called via glUnmapBufferARB(). |
||
355 | */ |
||
356 | static GLboolean |
||
357 | st_bufferobj_unmap(struct gl_context *ctx, GLenum target, struct gl_buffer_object *obj) |
||
358 | { |
||
359 | struct pipe_context *pipe = st_context(ctx)->pipe; |
||
360 | struct st_buffer_object *st_obj = st_buffer_object(obj); |
||
361 | |||
362 | if (obj->Length) |
||
363 | pipe_buffer_unmap(pipe, st_obj->buffer, st_obj->transfer); |
||
364 | |||
365 | st_obj->transfer = NULL; |
||
366 | obj->Pointer = NULL; |
||
367 | obj->Offset = 0; |
||
368 | obj->Length = 0; |
||
369 | return GL_TRUE; |
||
370 | } |
||
371 | |||
372 | |||
373 | /** |
||
374 | * Called via glCopyBufferSubData(). |
||
375 | */ |
||
376 | static void |
||
377 | st_copy_buffer_subdata(struct gl_context *ctx, |
||
378 | struct gl_buffer_object *src, |
||
379 | struct gl_buffer_object *dst, |
||
380 | GLintptr readOffset, GLintptr writeOffset, |
||
381 | GLsizeiptr size) |
||
382 | { |
||
383 | struct pipe_context *pipe = st_context(ctx)->pipe; |
||
384 | struct st_buffer_object *srcObj = st_buffer_object(src); |
||
385 | struct st_buffer_object *dstObj = st_buffer_object(dst); |
||
386 | struct pipe_transfer *src_transfer; |
||
387 | struct pipe_transfer *dst_transfer; |
||
388 | ubyte *srcPtr, *dstPtr; |
||
389 | |||
390 | if(!size) |
||
391 | return; |
||
392 | |||
393 | /* buffer should not already be mapped */ |
||
394 | assert(!src->Pointer); |
||
395 | assert(!dst->Pointer); |
||
396 | |||
397 | srcPtr = (ubyte *) pipe_buffer_map_range(pipe, |
||
398 | srcObj->buffer, |
||
399 | readOffset, size, |
||
400 | PIPE_TRANSFER_READ, |
||
401 | &src_transfer); |
||
402 | |||
403 | dstPtr = (ubyte *) pipe_buffer_map_range(pipe, |
||
404 | dstObj->buffer, |
||
405 | writeOffset, size, |
||
406 | PIPE_TRANSFER_WRITE, |
||
407 | &dst_transfer); |
||
408 | |||
409 | if (srcPtr && dstPtr) |
||
410 | memcpy(dstPtr + writeOffset, srcPtr + readOffset, size); |
||
411 | |||
412 | pipe_buffer_unmap(pipe, srcObj->buffer, src_transfer); |
||
413 | pipe_buffer_unmap(pipe, dstObj->buffer, dst_transfer); |
||
414 | } |
||
415 | |||
416 | |||
417 | /* TODO: if buffer wasn't created with appropriate usage flags, need |
||
418 | * to recreate it now and copy contents -- or possibly create a |
||
419 | * gallium entrypoint to extend the usage flags and let the driver |
||
420 | * decide if a copy is necessary. |
||
421 | */ |
||
422 | void |
||
423 | st_bufferobj_validate_usage(struct st_context *st, |
||
424 | struct st_buffer_object *obj, |
||
425 | unsigned usage) |
||
426 | { |
||
427 | } |
||
428 | |||
429 | |||
430 | void |
||
431 | st_init_bufferobject_functions(struct dd_function_table *functions) |
||
432 | { |
||
433 | functions->NewBufferObject = st_bufferobj_alloc; |
||
434 | functions->DeleteBuffer = st_bufferobj_free; |
||
435 | functions->BufferData = st_bufferobj_data; |
||
436 | functions->BufferSubData = st_bufferobj_subdata; |
||
437 | functions->GetBufferSubData = st_bufferobj_get_subdata; |
||
438 | functions->MapBuffer = st_bufferobj_map; |
||
439 | functions->MapBufferRange = st_bufferobj_map_range; |
||
440 | functions->FlushMappedBufferRange = st_bufferobj_flush_mapped_range; |
||
441 | functions->UnmapBuffer = st_bufferobj_unmap; |
||
442 | functions->CopyBufferSubData = st_copy_buffer_subdata; |
||
443 | |||
444 | /* For GL_APPLE_vertex_array_object */ |
||
445 | functions->NewArrayObject = _mesa_new_array_object; |
||
446 | functions->DeleteArrayObject = _mesa_delete_array_object; |
||
447 | }=>=>>=>=> |