mesa/st: implement memory objects as a backend for buffer objects
[mesa.git] / src / mesa / state_tracker / st_cb_bufferobjects.c
1 /**************************************************************************
2 *
3 * Copyright 2007 VMware, Inc.
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 VMWARE 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 <inttypes.h> /* for PRId64 macro */
35
36 #include "main/imports.h"
37 #include "main/mtypes.h"
38 #include "main/arrayobj.h"
39 #include "main/bufferobj.h"
40
41 #include "st_context.h"
42 #include "st_cb_bufferobjects.h"
43 #include "st_cb_memoryobjects.h"
44 #include "st_debug.h"
45
46 #include "pipe/p_context.h"
47 #include "pipe/p_defines.h"
48 #include "util/u_inlines.h"
49
50
51 /**
52 * There is some duplication between mesa's bufferobjects and our
53 * bufmgr buffers. Both have an integer handle and a hashtable to
54 * lookup an opaque structure. It would be nice if the handles and
55 * internal structure where somehow shared.
56 */
57 static struct gl_buffer_object *
58 st_bufferobj_alloc(struct gl_context *ctx, GLuint name)
59 {
60 struct st_buffer_object *st_obj = ST_CALLOC_STRUCT(st_buffer_object);
61
62 if (!st_obj)
63 return NULL;
64
65 _mesa_initialize_buffer_object(ctx, &st_obj->Base, name);
66
67 return &st_obj->Base;
68 }
69
70
71
72 /**
73 * Deallocate/free a vertex/pixel buffer object.
74 * Called via glDeleteBuffersARB().
75 */
76 static void
77 st_bufferobj_free(struct gl_context *ctx, struct gl_buffer_object *obj)
78 {
79 struct st_buffer_object *st_obj = st_buffer_object(obj);
80
81 assert(obj->RefCount == 0);
82 _mesa_buffer_unmap_all_mappings(ctx, obj);
83
84 if (st_obj->buffer)
85 pipe_resource_reference(&st_obj->buffer, NULL);
86
87 _mesa_delete_buffer_object(ctx, obj);
88 }
89
90
91
92 /**
93 * Replace data in a subrange of buffer object. If the data range
94 * specified by size + offset extends beyond the end of the buffer or
95 * if data is NULL, no copy is performed.
96 * Called via glBufferSubDataARB().
97 */
98 static void
99 st_bufferobj_subdata(struct gl_context *ctx,
100 GLintptrARB offset,
101 GLsizeiptrARB size,
102 const void * data, struct gl_buffer_object *obj)
103 {
104 struct st_buffer_object *st_obj = st_buffer_object(obj);
105
106 /* we may be called from VBO code, so double-check params here */
107 assert(offset >= 0);
108 assert(size >= 0);
109 assert(offset + size <= obj->Size);
110
111 if (!size)
112 return;
113
114 /*
115 * According to ARB_vertex_buffer_object specification, if data is null,
116 * then the contents of the buffer object's data store is undefined. We just
117 * ignore, and leave it unchanged.
118 */
119 if (!data)
120 return;
121
122 if (!st_obj->buffer) {
123 /* we probably ran out of memory during buffer allocation */
124 return;
125 }
126
127 /* Now that transfers are per-context, we don't have to figure out
128 * flushing here. Usually drivers won't need to flush in this case
129 * even if the buffer is currently referenced by hardware - they
130 * just queue the upload as dma rather than mapping the underlying
131 * buffer directly.
132 */
133 pipe_buffer_write(st_context(ctx)->pipe,
134 st_obj->buffer,
135 offset, size, data);
136 }
137
138
139 /**
140 * Called via glGetBufferSubDataARB().
141 */
142 static void
143 st_bufferobj_get_subdata(struct gl_context *ctx,
144 GLintptrARB offset,
145 GLsizeiptrARB size,
146 void * data, struct gl_buffer_object *obj)
147 {
148 struct st_buffer_object *st_obj = st_buffer_object(obj);
149
150 /* we may be called from VBO code, so double-check params here */
151 assert(offset >= 0);
152 assert(size >= 0);
153 assert(offset + size <= obj->Size);
154
155 if (!size)
156 return;
157
158 if (!st_obj->buffer) {
159 /* we probably ran out of memory during buffer allocation */
160 return;
161 }
162
163 pipe_buffer_read(st_context(ctx)->pipe, st_obj->buffer,
164 offset, size, data);
165 }
166
167 static ALWAYS_INLINE GLboolean
168 bufferobj_data(struct gl_context *ctx,
169 GLenum target,
170 GLsizeiptrARB size,
171 const void *data,
172 struct gl_memory_object *memObj,
173 GLuint64 offset,
174 GLenum usage,
175 GLbitfield storageFlags,
176 struct gl_buffer_object *obj)
177 {
178 struct st_context *st = st_context(ctx);
179 struct pipe_context *pipe = st->pipe;
180 struct pipe_screen *screen = pipe->screen;
181 struct st_buffer_object *st_obj = st_buffer_object(obj);
182 struct st_memory_object *st_mem_obj = st_memory_object(memObj);
183 unsigned bind, pipe_usage, pipe_flags = 0;
184
185 if (target != GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD &&
186 size && st_obj->buffer &&
187 st_obj->Base.Size == size &&
188 st_obj->Base.Usage == usage &&
189 st_obj->Base.StorageFlags == storageFlags) {
190 if (data) {
191 /* Just discard the old contents and write new data.
192 * This should be the same as creating a new buffer, but we avoid
193 * a lot of validation in Mesa.
194 */
195 pipe->buffer_subdata(pipe, st_obj->buffer,
196 PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE,
197 0, size, data);
198 return GL_TRUE;
199 } else if (screen->get_param(screen, PIPE_CAP_INVALIDATE_BUFFER)) {
200 pipe->invalidate_resource(pipe, st_obj->buffer);
201 return GL_TRUE;
202 }
203 }
204
205 st_obj->Base.Size = size;
206 st_obj->Base.Usage = usage;
207 st_obj->Base.StorageFlags = storageFlags;
208
209 switch (target) {
210 case GL_PIXEL_PACK_BUFFER_ARB:
211 case GL_PIXEL_UNPACK_BUFFER_ARB:
212 bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
213 break;
214 case GL_ARRAY_BUFFER_ARB:
215 bind = PIPE_BIND_VERTEX_BUFFER;
216 break;
217 case GL_ELEMENT_ARRAY_BUFFER_ARB:
218 bind = PIPE_BIND_INDEX_BUFFER;
219 break;
220 case GL_TEXTURE_BUFFER:
221 bind = PIPE_BIND_SAMPLER_VIEW;
222 break;
223 case GL_TRANSFORM_FEEDBACK_BUFFER:
224 bind = PIPE_BIND_STREAM_OUTPUT;
225 break;
226 case GL_UNIFORM_BUFFER:
227 bind = PIPE_BIND_CONSTANT_BUFFER;
228 break;
229 case GL_DRAW_INDIRECT_BUFFER:
230 case GL_PARAMETER_BUFFER_ARB:
231 bind = PIPE_BIND_COMMAND_ARGS_BUFFER;
232 break;
233 case GL_ATOMIC_COUNTER_BUFFER:
234 case GL_SHADER_STORAGE_BUFFER:
235 bind = PIPE_BIND_SHADER_BUFFER;
236 break;
237 case GL_QUERY_BUFFER:
238 bind = PIPE_BIND_QUERY_BUFFER;
239 break;
240 default:
241 bind = 0;
242 }
243
244 /* Set usage. */
245 if (st_obj->Base.Immutable) {
246 /* BufferStorage */
247 if (storageFlags & GL_CLIENT_STORAGE_BIT) {
248 if (storageFlags & GL_MAP_READ_BIT)
249 pipe_usage = PIPE_USAGE_STAGING;
250 else
251 pipe_usage = PIPE_USAGE_STREAM;
252 } else {
253 pipe_usage = PIPE_USAGE_DEFAULT;
254 }
255 }
256 else {
257 /* BufferData */
258 switch (usage) {
259 case GL_STATIC_DRAW:
260 case GL_STATIC_COPY:
261 default:
262 pipe_usage = PIPE_USAGE_DEFAULT;
263 break;
264 case GL_DYNAMIC_DRAW:
265 case GL_DYNAMIC_COPY:
266 pipe_usage = PIPE_USAGE_DYNAMIC;
267 break;
268 case GL_STREAM_DRAW:
269 case GL_STREAM_COPY:
270 /* XXX: Remove this test and fall-through when we have PBO unpacking
271 * acceleration. Right now, PBO unpacking is done by the CPU, so we
272 * have to make sure CPU reads are fast.
273 */
274 if (target != GL_PIXEL_UNPACK_BUFFER_ARB) {
275 pipe_usage = PIPE_USAGE_STREAM;
276 break;
277 }
278 /* fall through */
279 case GL_STATIC_READ:
280 case GL_DYNAMIC_READ:
281 case GL_STREAM_READ:
282 pipe_usage = PIPE_USAGE_STAGING;
283 break;
284 }
285 }
286
287 /* Set flags. */
288 if (storageFlags & GL_MAP_PERSISTENT_BIT)
289 pipe_flags |= PIPE_RESOURCE_FLAG_MAP_PERSISTENT;
290 if (storageFlags & GL_MAP_COHERENT_BIT)
291 pipe_flags |= PIPE_RESOURCE_FLAG_MAP_COHERENT;
292 if (storageFlags & GL_SPARSE_STORAGE_BIT_ARB)
293 pipe_flags |= PIPE_RESOURCE_FLAG_SPARSE;
294
295 pipe_resource_reference( &st_obj->buffer, NULL );
296
297 if (ST_DEBUG & DEBUG_BUFFER) {
298 debug_printf("Create buffer size %" PRId64 " bind 0x%x\n",
299 (int64_t) size, bind);
300 }
301
302 if (size != 0) {
303 struct pipe_resource buffer;
304
305 memset(&buffer, 0, sizeof buffer);
306 buffer.target = PIPE_BUFFER;
307 buffer.format = PIPE_FORMAT_R8_UNORM; /* want TYPELESS or similar */
308 buffer.bind = bind;
309 buffer.usage = pipe_usage;
310 buffer.flags = pipe_flags;
311 buffer.width0 = size;
312 buffer.height0 = 1;
313 buffer.depth0 = 1;
314 buffer.array_size = 1;
315
316 if (st_mem_obj) {
317 st_obj->buffer = screen->resource_from_memobj(screen, &buffer,
318 st_mem_obj->memory,
319 offset);
320 }
321 else if (target == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD) {
322 st_obj->buffer =
323 screen->resource_from_user_memory(screen, &buffer, (void*)data);
324 }
325 else {
326 st_obj->buffer = screen->resource_create(screen, &buffer);
327
328 if (st_obj->buffer && data)
329 pipe_buffer_write(pipe, st_obj->buffer, 0, size, data);
330 }
331
332 if (!st_obj->buffer) {
333 /* out of memory */
334 st_obj->Base.Size = 0;
335 return GL_FALSE;
336 }
337 }
338
339 /* The current buffer may be bound, so we have to revalidate all atoms that
340 * might be using it.
341 */
342 /* TODO: Add arrays to usage history */
343 ctx->NewDriverState |= ST_NEW_VERTEX_ARRAYS;
344 if (st_obj->Base.UsageHistory & USAGE_UNIFORM_BUFFER)
345 ctx->NewDriverState |= ST_NEW_UNIFORM_BUFFER;
346 if (st_obj->Base.UsageHistory & USAGE_SHADER_STORAGE_BUFFER)
347 ctx->NewDriverState |= ST_NEW_STORAGE_BUFFER;
348 if (st_obj->Base.UsageHistory & USAGE_TEXTURE_BUFFER)
349 ctx->NewDriverState |= ST_NEW_SAMPLER_VIEWS | ST_NEW_IMAGE_UNITS;
350 if (st_obj->Base.UsageHistory & USAGE_ATOMIC_COUNTER_BUFFER)
351 ctx->NewDriverState |= ST_NEW_ATOMIC_BUFFER;
352
353 return GL_TRUE;
354 }
355
356 /**
357 * Allocate space for and store data in a buffer object. Any data that was
358 * previously stored in the buffer object is lost. If data is NULL,
359 * memory will be allocated, but no copy will occur.
360 * Called via ctx->Driver.BufferData().
361 * \return GL_TRUE for success, GL_FALSE if out of memory
362 */
363 static GLboolean
364 st_bufferobj_data(struct gl_context *ctx,
365 GLenum target,
366 GLsizeiptrARB size,
367 const void *data,
368 GLenum usage,
369 GLbitfield storageFlags,
370 struct gl_buffer_object *obj)
371 {
372 return bufferobj_data(ctx, target, size, data, NULL, 0, usage, storageFlags, obj);
373 }
374
375 static GLboolean
376 st_bufferobj_data_mem(struct gl_context *ctx,
377 GLenum target,
378 GLsizeiptrARB size,
379 struct gl_memory_object *memObj,
380 GLuint64 offset,
381 GLenum usage,
382 struct gl_buffer_object *bufObj)
383 {
384 return bufferobj_data(ctx, target, size, NULL, memObj, offset, usage, 0, bufObj);
385 }
386
387 /**
388 * Called via glInvalidateBuffer(Sub)Data.
389 */
390 static void
391 st_bufferobj_invalidate(struct gl_context *ctx,
392 struct gl_buffer_object *obj,
393 GLintptr offset,
394 GLsizeiptr size)
395 {
396 struct st_context *st = st_context(ctx);
397 struct pipe_context *pipe = st->pipe;
398 struct st_buffer_object *st_obj = st_buffer_object(obj);
399
400 /* We ignore partial invalidates. */
401 if (offset != 0 || size != obj->Size)
402 return;
403
404 /* Nothing to invalidate. */
405 if (!st_obj->buffer)
406 return;
407
408 pipe->invalidate_resource(pipe, st_obj->buffer);
409 }
410
411
412 /**
413 * Called via glMapBufferRange().
414 */
415 static void *
416 st_bufferobj_map_range(struct gl_context *ctx,
417 GLintptr offset, GLsizeiptr length, GLbitfield access,
418 struct gl_buffer_object *obj,
419 gl_map_buffer_index index)
420 {
421 struct pipe_context *pipe = st_context(ctx)->pipe;
422 struct st_buffer_object *st_obj = st_buffer_object(obj);
423 enum pipe_transfer_usage flags = 0x0;
424
425 if (access & GL_MAP_WRITE_BIT)
426 flags |= PIPE_TRANSFER_WRITE;
427
428 if (access & GL_MAP_READ_BIT)
429 flags |= PIPE_TRANSFER_READ;
430
431 if (access & GL_MAP_FLUSH_EXPLICIT_BIT)
432 flags |= PIPE_TRANSFER_FLUSH_EXPLICIT;
433
434 if (access & GL_MAP_INVALIDATE_BUFFER_BIT) {
435 flags |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
436 }
437 else if (access & GL_MAP_INVALIDATE_RANGE_BIT) {
438 if (offset == 0 && length == obj->Size)
439 flags |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
440 else
441 flags |= PIPE_TRANSFER_DISCARD_RANGE;
442 }
443
444 if (access & GL_MAP_UNSYNCHRONIZED_BIT)
445 flags |= PIPE_TRANSFER_UNSYNCHRONIZED;
446
447 if (access & GL_MAP_PERSISTENT_BIT)
448 flags |= PIPE_TRANSFER_PERSISTENT;
449
450 if (access & GL_MAP_COHERENT_BIT)
451 flags |= PIPE_TRANSFER_COHERENT;
452
453 /* ... other flags ...
454 */
455
456 if (access & MESA_MAP_NOWAIT_BIT)
457 flags |= PIPE_TRANSFER_DONTBLOCK;
458
459 assert(offset >= 0);
460 assert(length >= 0);
461 assert(offset < obj->Size);
462 assert(offset + length <= obj->Size);
463
464 obj->Mappings[index].Pointer = pipe_buffer_map_range(pipe,
465 st_obj->buffer,
466 offset, length,
467 flags,
468 &st_obj->transfer[index]);
469 if (obj->Mappings[index].Pointer) {
470 obj->Mappings[index].Offset = offset;
471 obj->Mappings[index].Length = length;
472 obj->Mappings[index].AccessFlags = access;
473 }
474 else {
475 st_obj->transfer[index] = NULL;
476 }
477
478 return obj->Mappings[index].Pointer;
479 }
480
481
482 static void
483 st_bufferobj_flush_mapped_range(struct gl_context *ctx,
484 GLintptr offset, GLsizeiptr length,
485 struct gl_buffer_object *obj,
486 gl_map_buffer_index index)
487 {
488 struct pipe_context *pipe = st_context(ctx)->pipe;
489 struct st_buffer_object *st_obj = st_buffer_object(obj);
490
491 /* Subrange is relative to mapped range */
492 assert(offset >= 0);
493 assert(length >= 0);
494 assert(offset + length <= obj->Mappings[index].Length);
495 assert(obj->Mappings[index].Pointer);
496
497 if (!length)
498 return;
499
500 pipe_buffer_flush_mapped_range(pipe, st_obj->transfer[index],
501 obj->Mappings[index].Offset + offset,
502 length);
503 }
504
505
506 /**
507 * Called via glUnmapBufferARB().
508 */
509 static GLboolean
510 st_bufferobj_unmap(struct gl_context *ctx, struct gl_buffer_object *obj,
511 gl_map_buffer_index index)
512 {
513 struct pipe_context *pipe = st_context(ctx)->pipe;
514 struct st_buffer_object *st_obj = st_buffer_object(obj);
515
516 if (obj->Mappings[index].Length)
517 pipe_buffer_unmap(pipe, st_obj->transfer[index]);
518
519 st_obj->transfer[index] = NULL;
520 obj->Mappings[index].Pointer = NULL;
521 obj->Mappings[index].Offset = 0;
522 obj->Mappings[index].Length = 0;
523 return GL_TRUE;
524 }
525
526
527 /**
528 * Called via glCopyBufferSubData().
529 */
530 static void
531 st_copy_buffer_subdata(struct gl_context *ctx,
532 struct gl_buffer_object *src,
533 struct gl_buffer_object *dst,
534 GLintptr readOffset, GLintptr writeOffset,
535 GLsizeiptr size)
536 {
537 struct pipe_context *pipe = st_context(ctx)->pipe;
538 struct st_buffer_object *srcObj = st_buffer_object(src);
539 struct st_buffer_object *dstObj = st_buffer_object(dst);
540 struct pipe_box box;
541
542 if (!size)
543 return;
544
545 /* buffer should not already be mapped */
546 assert(!_mesa_check_disallowed_mapping(src));
547 assert(!_mesa_check_disallowed_mapping(dst));
548
549 u_box_1d(readOffset, size, &box);
550
551 pipe->resource_copy_region(pipe, dstObj->buffer, 0, writeOffset, 0, 0,
552 srcObj->buffer, 0, &box);
553 }
554
555 /**
556 * Called via glClearBufferSubData().
557 */
558 static void
559 st_clear_buffer_subdata(struct gl_context *ctx,
560 GLintptr offset, GLsizeiptr size,
561 const void *clearValue,
562 GLsizeiptr clearValueSize,
563 struct gl_buffer_object *bufObj)
564 {
565 struct pipe_context *pipe = st_context(ctx)->pipe;
566 struct st_buffer_object *buf = st_buffer_object(bufObj);
567 static const char zeros[16] = {0};
568
569 if (!pipe->clear_buffer) {
570 _mesa_ClearBufferSubData_sw(ctx, offset, size,
571 clearValue, clearValueSize, bufObj);
572 return;
573 }
574
575 if (!clearValue)
576 clearValue = zeros;
577
578 pipe->clear_buffer(pipe, buf->buffer, offset, size,
579 clearValue, clearValueSize);
580 }
581
582 static void
583 st_bufferobj_page_commitment(struct gl_context *ctx,
584 struct gl_buffer_object *bufferObj,
585 GLintptr offset, GLsizeiptr size,
586 GLboolean commit)
587 {
588 struct pipe_context *pipe = st_context(ctx)->pipe;
589 struct st_buffer_object *buf = st_buffer_object(bufferObj);
590 struct pipe_box box;
591
592 u_box_1d(offset, size, &box);
593
594 if (!pipe->resource_commit(pipe, buf->buffer, 0, &box, commit)) {
595 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferPageCommitmentARB(out of memory)");
596 return;
597 }
598 }
599
600 void
601 st_init_bufferobject_functions(struct pipe_screen *screen,
602 struct dd_function_table *functions)
603 {
604 functions->NewBufferObject = st_bufferobj_alloc;
605 functions->DeleteBuffer = st_bufferobj_free;
606 functions->BufferData = st_bufferobj_data;
607 functions->BufferDataMem = st_bufferobj_data_mem;
608 functions->BufferSubData = st_bufferobj_subdata;
609 functions->GetBufferSubData = st_bufferobj_get_subdata;
610 functions->MapBufferRange = st_bufferobj_map_range;
611 functions->FlushMappedBufferRange = st_bufferobj_flush_mapped_range;
612 functions->UnmapBuffer = st_bufferobj_unmap;
613 functions->CopyBufferSubData = st_copy_buffer_subdata;
614 functions->ClearBufferSubData = st_clear_buffer_subdata;
615 functions->BufferPageCommitment = st_bufferobj_page_commitment;
616
617 if (screen->get_param(screen, PIPE_CAP_INVALIDATE_BUFFER))
618 functions->InvalidateBufferSubData = st_bufferobj_invalidate;
619 }