Merge branch 'gallium-polygon-stipple'
[mesa.git] / src / mesa / drivers / dri / intel / intel_buffer_objects.c
1 /**************************************************************************
2 *
3 * Copyright 2003 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 #include "main/imports.h"
30 #include "main/mfeatures.h"
31 #include "main/mtypes.h"
32 #include "main/macros.h"
33 #include "main/bufferobj.h"
34
35 #include "intel_blit.h"
36 #include "intel_buffer_objects.h"
37 #include "intel_batchbuffer.h"
38 #include "intel_context.h"
39 #include "intel_fbo.h"
40 #include "intel_mipmap_tree.h"
41 #include "intel_regions.h"
42
43 static GLboolean
44 intel_bufferobj_unmap(struct gl_context * ctx,
45 GLenum target, struct gl_buffer_object *obj);
46
47 /** Allocates a new drm_intel_bo to store the data for the buffer object. */
48 static void
49 intel_bufferobj_alloc_buffer(struct intel_context *intel,
50 struct intel_buffer_object *intel_obj)
51 {
52 intel_obj->buffer = drm_intel_bo_alloc(intel->bufmgr, "bufferobj",
53 intel_obj->Base.Size, 64);
54 }
55
56 static void
57 release_buffer(struct intel_buffer_object *intel_obj)
58 {
59 drm_intel_bo_unreference(intel_obj->buffer);
60 intel_obj->buffer = NULL;
61 intel_obj->offset = 0;
62 intel_obj->source = 0;
63 }
64
65 /**
66 * There is some duplication between mesa's bufferobjects and our
67 * bufmgr buffers. Both have an integer handle and a hashtable to
68 * lookup an opaque structure. It would be nice if the handles and
69 * internal structure where somehow shared.
70 */
71 static struct gl_buffer_object *
72 intel_bufferobj_alloc(struct gl_context * ctx, GLuint name, GLenum target)
73 {
74 struct intel_buffer_object *obj = CALLOC_STRUCT(intel_buffer_object);
75
76 _mesa_initialize_buffer_object(&obj->Base, name, target);
77
78 obj->buffer = NULL;
79
80 return &obj->Base;
81 }
82
83 /* Break the COW tie to the region. The region gets to keep the data.
84 */
85 void
86 intel_bufferobj_release_region(struct intel_context *intel,
87 struct intel_buffer_object *intel_obj)
88 {
89 assert(intel_obj->region->buffer == intel_obj->buffer);
90 intel_obj->region->pbo = NULL;
91 intel_obj->region = NULL;
92
93 release_buffer(intel_obj);
94 }
95
96 /* Break the COW tie to the region. Both the pbo and the region end
97 * up with a copy of the data.
98 */
99 void
100 intel_bufferobj_cow(struct intel_context *intel,
101 struct intel_buffer_object *intel_obj)
102 {
103 assert(intel_obj->region);
104 intel_region_cow(intel, intel_obj->region);
105 }
106
107
108 /**
109 * Deallocate/free a vertex/pixel buffer object.
110 * Called via glDeleteBuffersARB().
111 */
112 static void
113 intel_bufferobj_free(struct gl_context * ctx, struct gl_buffer_object *obj)
114 {
115 struct intel_context *intel = intel_context(ctx);
116 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
117
118 assert(intel_obj);
119
120 /* Buffer objects are automatically unmapped when deleting according
121 * to the spec, but Mesa doesn't do UnmapBuffer for us at context destroy
122 * (though it does if you call glDeleteBuffers)
123 */
124 if (obj->Pointer)
125 intel_bufferobj_unmap(ctx, 0, obj);
126
127 free(intel_obj->sys_buffer);
128 if (intel_obj->region) {
129 intel_bufferobj_release_region(intel, intel_obj);
130 }
131
132 drm_intel_bo_unreference(intel_obj->buffer);
133 free(intel_obj);
134 }
135
136
137
138 /**
139 * Allocate space for and store data in a buffer object. Any data that was
140 * previously stored in the buffer object is lost. If data is NULL,
141 * memory will be allocated, but no copy will occur.
142 * Called via ctx->Driver.BufferData().
143 * \return GL_TRUE for success, GL_FALSE if out of memory
144 */
145 static GLboolean
146 intel_bufferobj_data(struct gl_context * ctx,
147 GLenum target,
148 GLsizeiptrARB size,
149 const GLvoid * data,
150 GLenum usage, struct gl_buffer_object *obj)
151 {
152 struct intel_context *intel = intel_context(ctx);
153 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
154
155 intel_obj->Base.Size = size;
156 intel_obj->Base.Usage = usage;
157
158 assert(!obj->Pointer); /* Mesa should have unmapped it */
159
160 if (intel_obj->region)
161 intel_bufferobj_release_region(intel, intel_obj);
162
163 if (intel_obj->buffer != NULL)
164 release_buffer(intel_obj);
165
166 free(intel_obj->sys_buffer);
167 intel_obj->sys_buffer = NULL;
168
169 if (size != 0) {
170 if (usage == GL_DYNAMIC_DRAW
171 #ifdef I915
172 /* On pre-965, stick VBOs in system memory, as we're always doing
173 * swtnl with their contents anyway.
174 */
175 || target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER
176 #endif
177 )
178 {
179 intel_obj->sys_buffer = malloc(size);
180 if (intel_obj->sys_buffer != NULL) {
181 if (data != NULL)
182 memcpy(intel_obj->sys_buffer, data, size);
183 return GL_TRUE;
184 }
185 }
186 intel_bufferobj_alloc_buffer(intel, intel_obj);
187 if (!intel_obj->buffer)
188 return GL_FALSE;
189
190 if (data != NULL)
191 drm_intel_bo_subdata(intel_obj->buffer, 0, size, data);
192 }
193
194 return GL_TRUE;
195 }
196
197
198 /**
199 * Replace data in a subrange of buffer object. If the data range
200 * specified by size + offset extends beyond the end of the buffer or
201 * if data is NULL, no copy is performed.
202 * Called via glBufferSubDataARB().
203 */
204 static void
205 intel_bufferobj_subdata(struct gl_context * ctx,
206 GLenum target,
207 GLintptrARB offset,
208 GLsizeiptrARB size,
209 const GLvoid * data, struct gl_buffer_object *obj)
210 {
211 struct intel_context *intel = intel_context(ctx);
212 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
213 bool busy;
214
215 if (size == 0)
216 return;
217
218 assert(intel_obj);
219
220 if (intel_obj->region)
221 intel_bufferobj_cow(intel, intel_obj);
222
223 /* If we have a single copy in system memory, update that */
224 if (intel_obj->sys_buffer) {
225 if (intel_obj->source)
226 release_buffer(intel_obj);
227
228 if (intel_obj->buffer == NULL) {
229 memcpy((char *)intel_obj->sys_buffer + offset, data, size);
230 return;
231 }
232
233 free(intel_obj->sys_buffer);
234 intel_obj->sys_buffer = NULL;
235 }
236
237 /* Otherwise we need to update the copy in video memory. */
238 busy =
239 drm_intel_bo_busy(intel_obj->buffer) ||
240 drm_intel_bo_references(intel->batch.bo, intel_obj->buffer);
241
242 /* replace the current busy bo with fresh data */
243 if (busy && size == intel_obj->Base.Size) {
244 drm_intel_bo_unreference(intel_obj->buffer);
245 intel_bufferobj_alloc_buffer(intel, intel_obj);
246 drm_intel_bo_subdata(intel_obj->buffer, 0, size, data);
247 } else if (intel->gen < 6) {
248 if (busy) {
249 drm_intel_bo *temp_bo;
250
251 temp_bo = drm_intel_bo_alloc(intel->bufmgr, "subdata temp", size, 64);
252
253 drm_intel_bo_subdata(temp_bo, 0, size, data);
254
255 intel_emit_linear_blit(intel,
256 intel_obj->buffer, offset,
257 temp_bo, 0,
258 size);
259
260 drm_intel_bo_unreference(temp_bo);
261 } else {
262 drm_intel_bo_subdata(intel_obj->buffer, offset, size, data);
263 }
264 } else {
265 /* Can't use the blit to modify the buffer in the middle of batch. */
266 if (drm_intel_bo_references(intel->batch.bo, intel_obj->buffer)) {
267 intel_batchbuffer_flush(intel);
268 }
269 drm_intel_bo_subdata(intel_obj->buffer, offset, size, data);
270 }
271 }
272
273
274 /**
275 * Called via glGetBufferSubDataARB().
276 */
277 static void
278 intel_bufferobj_get_subdata(struct gl_context * ctx,
279 GLenum target,
280 GLintptrARB offset,
281 GLsizeiptrARB size,
282 GLvoid * data, struct gl_buffer_object *obj)
283 {
284 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
285
286 assert(intel_obj);
287 if (intel_obj->sys_buffer)
288 memcpy(data, (char *)intel_obj->sys_buffer + offset, size);
289 else
290 drm_intel_bo_get_subdata(intel_obj->buffer, offset, size, data);
291 }
292
293
294
295 /**
296 * Called via glMapBufferARB().
297 */
298 static void *
299 intel_bufferobj_map(struct gl_context * ctx,
300 GLenum target,
301 GLenum access, struct gl_buffer_object *obj)
302 {
303 struct intel_context *intel = intel_context(ctx);
304 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
305 GLboolean read_only = (access == GL_READ_ONLY_ARB);
306 GLboolean write_only = (access == GL_WRITE_ONLY_ARB);
307
308 assert(intel_obj);
309
310 if (intel_obj->sys_buffer) {
311 if (!read_only && intel_obj->source) {
312 release_buffer(intel_obj);
313 }
314
315 if (!intel_obj->buffer || intel_obj->source) {
316 obj->Pointer = intel_obj->sys_buffer;
317 obj->Length = obj->Size;
318 obj->Offset = 0;
319 return obj->Pointer;
320 }
321
322 free(intel_obj->sys_buffer);
323 intel_obj->sys_buffer = NULL;
324 }
325
326 /* Flush any existing batchbuffer that might reference this data. */
327 if (drm_intel_bo_references(intel->batch.bo, intel_obj->buffer))
328 intel_flush(ctx);
329
330 if (intel_obj->region)
331 intel_bufferobj_cow(intel, intel_obj);
332
333 if (intel_obj->buffer == NULL) {
334 obj->Pointer = NULL;
335 return NULL;
336 }
337
338 if (write_only) {
339 drm_intel_gem_bo_map_gtt(intel_obj->buffer);
340 intel_obj->mapped_gtt = GL_TRUE;
341 } else {
342 drm_intel_bo_map(intel_obj->buffer, !read_only);
343 intel_obj->mapped_gtt = GL_FALSE;
344 }
345
346 obj->Pointer = intel_obj->buffer->virtual;
347 obj->Length = obj->Size;
348 obj->Offset = 0;
349
350 return obj->Pointer;
351 }
352
353 /**
354 * Called via glMapBufferRange().
355 *
356 * The goal of this extension is to allow apps to accumulate their rendering
357 * at the same time as they accumulate their buffer object. Without it,
358 * you'd end up blocking on execution of rendering every time you mapped
359 * the buffer to put new data in.
360 *
361 * We support it in 3 ways: If unsynchronized, then don't bother
362 * flushing the batchbuffer before mapping the buffer, which can save blocking
363 * in many cases. If we would still block, and they allow the whole buffer
364 * to be invalidated, then just allocate a new buffer to replace the old one.
365 * If not, and we'd block, and they allow the subrange of the buffer to be
366 * invalidated, then we can make a new little BO, let them write into that,
367 * and blit it into the real BO at unmap time.
368 */
369 static void *
370 intel_bufferobj_map_range(struct gl_context * ctx,
371 GLenum target, GLintptr offset, GLsizeiptr length,
372 GLbitfield access, struct gl_buffer_object *obj)
373 {
374 struct intel_context *intel = intel_context(ctx);
375 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
376 GLboolean read_only = (access == GL_READ_ONLY_ARB);
377
378 assert(intel_obj);
379
380 /* _mesa_MapBufferRange (GL entrypoint) sets these, but the vbo module also
381 * internally uses our functions directly.
382 */
383 obj->Offset = offset;
384 obj->Length = length;
385 obj->AccessFlags = access;
386
387 if (intel_obj->sys_buffer) {
388 if (!read_only && intel_obj->source)
389 release_buffer(intel_obj);
390
391 if (!intel_obj->buffer || intel_obj->source) {
392 obj->Pointer = intel_obj->sys_buffer + offset;
393 return obj->Pointer;
394 }
395
396 free(intel_obj->sys_buffer);
397 intel_obj->sys_buffer = NULL;
398 }
399
400 if (intel_obj->region)
401 intel_bufferobj_cow(intel, intel_obj);
402
403 /* If the mapping is synchronized with other GL operations, flush
404 * the batchbuffer so that GEM knows about the buffer access for later
405 * syncing.
406 */
407 if (!(access & GL_MAP_UNSYNCHRONIZED_BIT) &&
408 drm_intel_bo_references(intel->batch.bo, intel_obj->buffer))
409 intel_flush(ctx);
410
411 if (intel_obj->buffer == NULL) {
412 obj->Pointer = NULL;
413 return NULL;
414 }
415
416 /* If the user doesn't care about existing buffer contents and mapping
417 * would cause us to block, then throw out the old buffer.
418 */
419 if (!(access & GL_MAP_UNSYNCHRONIZED_BIT) &&
420 (access & GL_MAP_INVALIDATE_BUFFER_BIT) &&
421 drm_intel_bo_busy(intel_obj->buffer)) {
422 drm_intel_bo_unreference(intel_obj->buffer);
423 intel_bufferobj_alloc_buffer(intel, intel_obj);
424 }
425
426 /* If the user is mapping a range of an active buffer object but
427 * doesn't require the current contents of that range, make a new
428 * BO, and we'll copy what they put in there out at unmap or
429 * FlushRange time.
430 */
431 if ((access & GL_MAP_INVALIDATE_RANGE_BIT) &&
432 drm_intel_bo_busy(intel_obj->buffer)) {
433 if (access & GL_MAP_FLUSH_EXPLICIT_BIT) {
434 intel_obj->range_map_buffer = malloc(length);
435 obj->Pointer = intel_obj->range_map_buffer;
436 } else {
437 intel_obj->range_map_bo = drm_intel_bo_alloc(intel->bufmgr,
438 "range map",
439 length, 64);
440 if (!(access & GL_MAP_READ_BIT)) {
441 drm_intel_gem_bo_map_gtt(intel_obj->range_map_bo);
442 intel_obj->mapped_gtt = GL_TRUE;
443 } else {
444 drm_intel_bo_map(intel_obj->range_map_bo,
445 (access & GL_MAP_WRITE_BIT) != 0);
446 intel_obj->mapped_gtt = GL_FALSE;
447 }
448 obj->Pointer = intel_obj->range_map_bo->virtual;
449 }
450 return obj->Pointer;
451 }
452
453 if (!(access & GL_MAP_READ_BIT)) {
454 drm_intel_gem_bo_map_gtt(intel_obj->buffer);
455 intel_obj->mapped_gtt = GL_TRUE;
456 } else {
457 drm_intel_bo_map(intel_obj->buffer, (access & GL_MAP_WRITE_BIT) != 0);
458 intel_obj->mapped_gtt = GL_FALSE;
459 }
460
461 obj->Pointer = intel_obj->buffer->virtual + offset;
462 return obj->Pointer;
463 }
464
465 /* Ideally we'd use a BO to avoid taking up cache space for the temporary
466 * data, but FlushMappedBufferRange may be followed by further writes to
467 * the pointer, so we would have to re-map after emitting our blit, which
468 * would defeat the point.
469 */
470 static void
471 intel_bufferobj_flush_mapped_range(struct gl_context *ctx, GLenum target,
472 GLintptr offset, GLsizeiptr length,
473 struct gl_buffer_object *obj)
474 {
475 struct intel_context *intel = intel_context(ctx);
476 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
477 drm_intel_bo *temp_bo;
478
479 /* Unless we're in the range map using a temporary system buffer,
480 * there's no work to do.
481 */
482 if (intel_obj->range_map_buffer == NULL)
483 return;
484
485 if (length == 0)
486 return;
487
488 temp_bo = drm_intel_bo_alloc(intel->bufmgr, "range map flush", length, 64);
489
490 drm_intel_bo_subdata(temp_bo, 0, length, intel_obj->range_map_buffer);
491
492 intel_emit_linear_blit(intel,
493 intel_obj->buffer, obj->Offset + offset,
494 temp_bo, 0,
495 length);
496
497 drm_intel_bo_unreference(temp_bo);
498 }
499
500
501 /**
502 * Called via glUnmapBuffer().
503 */
504 static GLboolean
505 intel_bufferobj_unmap(struct gl_context * ctx,
506 GLenum target, struct gl_buffer_object *obj)
507 {
508 struct intel_context *intel = intel_context(ctx);
509 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
510
511 assert(intel_obj);
512 assert(obj->Pointer);
513 if (intel_obj->sys_buffer != NULL) {
514 /* always keep the mapping around. */
515 } else if (intel_obj->range_map_buffer != NULL) {
516 /* Since we've emitted some blits to buffers that will (likely) be used
517 * in rendering operations in other cache domains in this batch, emit a
518 * flush. Once again, we wish for a domain tracker in libdrm to cover
519 * usage inside of a batchbuffer.
520 */
521 intel_batchbuffer_emit_mi_flush(intel);
522 free(intel_obj->range_map_buffer);
523 intel_obj->range_map_buffer = NULL;
524 } else if (intel_obj->range_map_bo != NULL) {
525 if (intel_obj->mapped_gtt) {
526 drm_intel_gem_bo_unmap_gtt(intel_obj->range_map_bo);
527 } else {
528 drm_intel_bo_unmap(intel_obj->range_map_bo);
529 }
530
531 intel_emit_linear_blit(intel,
532 intel_obj->buffer, obj->Offset,
533 intel_obj->range_map_bo, 0,
534 obj->Length);
535
536 /* Since we've emitted some blits to buffers that will (likely) be used
537 * in rendering operations in other cache domains in this batch, emit a
538 * flush. Once again, we wish for a domain tracker in libdrm to cover
539 * usage inside of a batchbuffer.
540 */
541 intel_batchbuffer_emit_mi_flush(intel);
542
543 drm_intel_bo_unreference(intel_obj->range_map_bo);
544 intel_obj->range_map_bo = NULL;
545 } else if (intel_obj->buffer != NULL) {
546 if (intel_obj->mapped_gtt) {
547 drm_intel_gem_bo_unmap_gtt(intel_obj->buffer);
548 } else {
549 drm_intel_bo_unmap(intel_obj->buffer);
550 }
551 }
552 obj->Pointer = NULL;
553 obj->Offset = 0;
554 obj->Length = 0;
555
556 return GL_TRUE;
557 }
558
559 drm_intel_bo *
560 intel_bufferobj_buffer(struct intel_context *intel,
561 struct intel_buffer_object *intel_obj,
562 GLuint flag)
563 {
564 if (intel_obj->region) {
565 if (flag == INTEL_WRITE_PART)
566 intel_bufferobj_cow(intel, intel_obj);
567 else if (flag == INTEL_WRITE_FULL) {
568 intel_bufferobj_release_region(intel, intel_obj);
569 intel_bufferobj_alloc_buffer(intel, intel_obj);
570 }
571 }
572
573 if (intel_obj->source)
574 release_buffer(intel_obj);
575
576 if (intel_obj->buffer == NULL) {
577 intel_bufferobj_alloc_buffer(intel, intel_obj);
578 drm_intel_bo_subdata(intel_obj->buffer,
579 0, intel_obj->Base.Size,
580 intel_obj->sys_buffer);
581
582 free(intel_obj->sys_buffer);
583 intel_obj->sys_buffer = NULL;
584 intel_obj->offset = 0;
585 }
586
587 return intel_obj->buffer;
588 }
589
590 #define INTEL_UPLOAD_SIZE (64*1024)
591
592 void
593 intel_upload_finish(struct intel_context *intel)
594 {
595 if (!intel->upload.bo)
596 return;
597
598 if (intel->upload.buffer_len) {
599 drm_intel_bo_subdata(intel->upload.bo,
600 intel->upload.buffer_offset,
601 intel->upload.buffer_len,
602 intel->upload.buffer);
603 intel->upload.buffer_len = 0;
604 }
605
606 drm_intel_bo_unreference(intel->upload.bo);
607 intel->upload.bo = NULL;
608 }
609
610 static void wrap_buffers(struct intel_context *intel, GLuint size)
611 {
612 intel_upload_finish(intel);
613
614 if (size < INTEL_UPLOAD_SIZE)
615 size = INTEL_UPLOAD_SIZE;
616
617 intel->upload.bo = drm_intel_bo_alloc(intel->bufmgr, "upload", size, 0);
618 intel->upload.offset = 0;
619 }
620
621 void intel_upload_data(struct intel_context *intel,
622 const void *ptr, GLuint size, GLuint align,
623 drm_intel_bo **return_bo,
624 GLuint *return_offset)
625 {
626 GLuint base, delta;
627
628 base = (intel->upload.offset + align - 1) / align * align;
629 if (intel->upload.bo == NULL || base + size > intel->upload.bo->size) {
630 wrap_buffers(intel, size);
631 base = 0;
632 }
633
634 drm_intel_bo_reference(intel->upload.bo);
635 *return_bo = intel->upload.bo;
636 *return_offset = base;
637
638 delta = base - intel->upload.offset;
639 if (intel->upload.buffer_len &&
640 intel->upload.buffer_len + delta + size > sizeof(intel->upload.buffer))
641 {
642 drm_intel_bo_subdata(intel->upload.bo,
643 intel->upload.buffer_offset,
644 intel->upload.buffer_len,
645 intel->upload.buffer);
646 intel->upload.buffer_len = 0;
647 }
648
649 if (size < sizeof(intel->upload.buffer))
650 {
651 if (intel->upload.buffer_len == 0)
652 intel->upload.buffer_offset = base;
653 else
654 intel->upload.buffer_len += delta;
655
656 memcpy(intel->upload.buffer + intel->upload.buffer_len, ptr, size);
657 intel->upload.buffer_len += size;
658 }
659 else
660 {
661 drm_intel_bo_subdata(intel->upload.bo, base, size, ptr);
662 }
663
664 intel->upload.offset = base + size;
665 }
666
667 void *intel_upload_map(struct intel_context *intel, GLuint size, GLuint align)
668 {
669 GLuint base, delta;
670 char *ptr;
671
672 base = (intel->upload.offset + align - 1) / align * align;
673 if (intel->upload.bo == NULL || base + size > intel->upload.bo->size) {
674 wrap_buffers(intel, size);
675 base = 0;
676 }
677
678 delta = base - intel->upload.offset;
679 if (intel->upload.buffer_len &&
680 intel->upload.buffer_len + delta + size > sizeof(intel->upload.buffer))
681 {
682 drm_intel_bo_subdata(intel->upload.bo,
683 intel->upload.buffer_offset,
684 intel->upload.buffer_len,
685 intel->upload.buffer);
686 intel->upload.buffer_len = 0;
687 }
688
689 if (size <= sizeof(intel->upload.buffer)) {
690 if (intel->upload.buffer_len == 0)
691 intel->upload.buffer_offset = base;
692 else
693 intel->upload.buffer_len += delta;
694
695 ptr = intel->upload.buffer + intel->upload.buffer_len;
696 intel->upload.buffer_len += size;
697 } else
698 ptr = malloc(size);
699
700 return ptr;
701 }
702
703 void intel_upload_unmap(struct intel_context *intel,
704 const void *ptr, GLuint size, GLuint align,
705 drm_intel_bo **return_bo,
706 GLuint *return_offset)
707 {
708 GLuint base;
709
710 base = (intel->upload.offset + align - 1) / align * align;
711 if (size > sizeof(intel->upload.buffer)) {
712 drm_intel_bo_subdata(intel->upload.bo, base, size, ptr);
713 free((void*)ptr);
714 }
715
716 drm_intel_bo_reference(intel->upload.bo);
717 *return_bo = intel->upload.bo;
718 *return_offset = base;
719
720 intel->upload.offset = base + size;
721 }
722
723 drm_intel_bo *
724 intel_bufferobj_source(struct intel_context *intel,
725 struct intel_buffer_object *intel_obj,
726 GLuint align, GLuint *offset)
727 {
728 if (intel_obj->buffer == NULL) {
729 intel_upload_data(intel,
730 intel_obj->sys_buffer, intel_obj->Base.Size, align,
731 &intel_obj->buffer, &intel_obj->offset);
732 intel_obj->source = 1;
733 }
734
735 *offset = intel_obj->offset;
736 return intel_obj->buffer;
737 }
738
739 static void
740 intel_bufferobj_copy_subdata(struct gl_context *ctx,
741 struct gl_buffer_object *src,
742 struct gl_buffer_object *dst,
743 GLintptr read_offset, GLintptr write_offset,
744 GLsizeiptr size)
745 {
746 struct intel_context *intel = intel_context(ctx);
747 struct intel_buffer_object *intel_src = intel_buffer_object(src);
748 struct intel_buffer_object *intel_dst = intel_buffer_object(dst);
749 drm_intel_bo *src_bo, *dst_bo;
750 GLuint src_offset;
751
752 if (size == 0)
753 return;
754
755 /* If we're in system memory, just map and memcpy. */
756 if (intel_src->sys_buffer || intel_dst->sys_buffer || intel->gen >= 6) {
757 /* The same buffer may be used, but note that regions copied may
758 * not overlap.
759 */
760 if (src == dst) {
761 char *ptr = intel_bufferobj_map(ctx, GL_COPY_WRITE_BUFFER,
762 GL_READ_WRITE, dst);
763 memmove(ptr + write_offset, ptr + read_offset, size);
764 intel_bufferobj_unmap(ctx, GL_COPY_WRITE_BUFFER, dst);
765 } else {
766 const char *src_ptr;
767 char *dst_ptr;
768
769 src_ptr = intel_bufferobj_map(ctx, GL_COPY_READ_BUFFER,
770 GL_READ_ONLY, src);
771 dst_ptr = intel_bufferobj_map(ctx, GL_COPY_WRITE_BUFFER,
772 GL_WRITE_ONLY, dst);
773
774 memcpy(dst_ptr + write_offset, src_ptr + read_offset, size);
775
776 intel_bufferobj_unmap(ctx, GL_COPY_READ_BUFFER, src);
777 intel_bufferobj_unmap(ctx, GL_COPY_WRITE_BUFFER, dst);
778 }
779 return;
780 }
781
782 /* Otherwise, we have real BOs, so blit them. */
783
784 dst_bo = intel_bufferobj_buffer(intel, intel_dst, INTEL_WRITE_PART);
785 src_bo = intel_bufferobj_source(intel, intel_src, 64, &src_offset);
786
787 intel_emit_linear_blit(intel,
788 dst_bo, write_offset,
789 src_bo, read_offset + src_offset, size);
790
791 /* Since we've emitted some blits to buffers that will (likely) be used
792 * in rendering operations in other cache domains in this batch, emit a
793 * flush. Once again, we wish for a domain tracker in libdrm to cover
794 * usage inside of a batchbuffer.
795 */
796 intel_batchbuffer_emit_mi_flush(intel);
797 }
798
799 #if FEATURE_APPLE_object_purgeable
800 static GLenum
801 intel_buffer_purgeable(struct gl_context * ctx,
802 drm_intel_bo *buffer,
803 GLenum option)
804 {
805 int retained = 0;
806
807 if (buffer != NULL)
808 retained = drm_intel_bo_madvise (buffer, I915_MADV_DONTNEED);
809
810 return retained ? GL_VOLATILE_APPLE : GL_RELEASED_APPLE;
811 }
812
813 static GLenum
814 intel_buffer_object_purgeable(struct gl_context * ctx,
815 struct gl_buffer_object *obj,
816 GLenum option)
817 {
818 struct intel_buffer_object *intel;
819
820 intel = intel_buffer_object (obj);
821 if (intel->buffer != NULL)
822 return intel_buffer_purgeable (ctx, intel->buffer, option);
823
824 if (option == GL_RELEASED_APPLE) {
825 if (intel->sys_buffer != NULL) {
826 free(intel->sys_buffer);
827 intel->sys_buffer = NULL;
828 }
829
830 return GL_RELEASED_APPLE;
831 } else {
832 /* XXX Create the buffer and madvise(MADV_DONTNEED)? */
833 return intel_buffer_purgeable (ctx,
834 intel_bufferobj_buffer(intel_context(ctx),
835 intel, INTEL_READ),
836 option);
837 }
838 }
839
840 static GLenum
841 intel_texture_object_purgeable(struct gl_context * ctx,
842 struct gl_texture_object *obj,
843 GLenum option)
844 {
845 struct intel_texture_object *intel;
846
847 intel = intel_texture_object(obj);
848 if (intel->mt == NULL || intel->mt->region == NULL)
849 return GL_RELEASED_APPLE;
850
851 return intel_buffer_purgeable (ctx, intel->mt->region->buffer, option);
852 }
853
854 static GLenum
855 intel_render_object_purgeable(struct gl_context * ctx,
856 struct gl_renderbuffer *obj,
857 GLenum option)
858 {
859 struct intel_renderbuffer *intel;
860
861 intel = intel_renderbuffer(obj);
862 if (intel->region == NULL)
863 return GL_RELEASED_APPLE;
864
865 return intel_buffer_purgeable (ctx, intel->region->buffer, option);
866 }
867
868 static GLenum
869 intel_buffer_unpurgeable(struct gl_context * ctx,
870 drm_intel_bo *buffer,
871 GLenum option)
872 {
873 int retained;
874
875 retained = 0;
876 if (buffer != NULL)
877 retained = drm_intel_bo_madvise (buffer, I915_MADV_WILLNEED);
878
879 return retained ? GL_RETAINED_APPLE : GL_UNDEFINED_APPLE;
880 }
881
882 static GLenum
883 intel_buffer_object_unpurgeable(struct gl_context * ctx,
884 struct gl_buffer_object *obj,
885 GLenum option)
886 {
887 return intel_buffer_unpurgeable (ctx, intel_buffer_object (obj)->buffer, option);
888 }
889
890 static GLenum
891 intel_texture_object_unpurgeable(struct gl_context * ctx,
892 struct gl_texture_object *obj,
893 GLenum option)
894 {
895 struct intel_texture_object *intel;
896
897 intel = intel_texture_object(obj);
898 if (intel->mt == NULL || intel->mt->region == NULL)
899 return GL_UNDEFINED_APPLE;
900
901 return intel_buffer_unpurgeable (ctx, intel->mt->region->buffer, option);
902 }
903
904 static GLenum
905 intel_render_object_unpurgeable(struct gl_context * ctx,
906 struct gl_renderbuffer *obj,
907 GLenum option)
908 {
909 struct intel_renderbuffer *intel;
910
911 intel = intel_renderbuffer(obj);
912 if (intel->region == NULL)
913 return GL_UNDEFINED_APPLE;
914
915 return intel_buffer_unpurgeable (ctx, intel->region->buffer, option);
916 }
917 #endif
918
919 void
920 intelInitBufferObjectFuncs(struct dd_function_table *functions)
921 {
922 functions->NewBufferObject = intel_bufferobj_alloc;
923 functions->DeleteBuffer = intel_bufferobj_free;
924 functions->BufferData = intel_bufferobj_data;
925 functions->BufferSubData = intel_bufferobj_subdata;
926 functions->GetBufferSubData = intel_bufferobj_get_subdata;
927 functions->MapBuffer = intel_bufferobj_map;
928 functions->MapBufferRange = intel_bufferobj_map_range;
929 functions->FlushMappedBufferRange = intel_bufferobj_flush_mapped_range;
930 functions->UnmapBuffer = intel_bufferobj_unmap;
931 functions->CopyBufferSubData = intel_bufferobj_copy_subdata;
932
933 #if FEATURE_APPLE_object_purgeable
934 functions->BufferObjectPurgeable = intel_buffer_object_purgeable;
935 functions->TextureObjectPurgeable = intel_texture_object_purgeable;
936 functions->RenderObjectPurgeable = intel_render_object_purgeable;
937
938 functions->BufferObjectUnpurgeable = intel_buffer_object_unpurgeable;
939 functions->TextureObjectUnpurgeable = intel_texture_object_unpurgeable;
940 functions->RenderObjectUnpurgeable = intel_render_object_unpurgeable;
941 #endif
942 }