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