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