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