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 
42 static GLboolean
43 intel_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. */
47 static void
intel_bufferobj_alloc_buffer(struct intel_context * intel,struct intel_buffer_object * intel_obj)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
release_buffer(struct intel_buffer_object * intel_obj)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 *
intel_bufferobj_alloc(struct gl_context * ctx,GLuint name)71 intel_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  */
86 static void
intel_bufferobj_free(struct gl_context * ctx,struct gl_buffer_object * obj)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    _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  */
114 static GLboolean
intel_bufferobj_data(struct gl_context * ctx,GLenum target,GLsizeiptrARB size,const GLvoid * data,GLenum usage,GLbitfield storageFlags,struct gl_buffer_object * obj)115 intel_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  */
171 static void
intel_bufferobj_subdata(struct gl_context * ctx,GLintptrARB offset,GLsizeiptrARB size,const GLvoid * data,struct gl_buffer_object * obj)172 intel_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  */
236 static void
intel_bufferobj_get_subdata(struct gl_context * ctx,GLintptrARB offset,GLsizeiptrARB size,GLvoid * data,struct gl_buffer_object * obj)237 intel_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  */
274 static void *
intel_bufferobj_map_range(struct gl_context * ctx,GLintptr offset,GLsizeiptr length,GLbitfield access,struct gl_buffer_object * obj,gl_map_buffer_index index)275 intel_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  */
390 static void
intel_bufferobj_flush_mapped_range(struct gl_context * ctx,GLintptr offset,GLsizeiptr length,struct gl_buffer_object * obj,gl_map_buffer_index index)391 intel_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  */
430 static GLboolean
intel_bufferobj_unmap(struct gl_context * ctx,struct gl_buffer_object * obj,gl_map_buffer_index index)431 intel_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 
480 drm_intel_bo *
intel_bufferobj_buffer(struct intel_context * intel,struct intel_buffer_object * intel_obj)481 intel_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 
503 void
intel_upload_finish(struct intel_context * intel)504 intel_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 
wrap_buffers(struct intel_context * intel,GLuint size)521 static 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 
intel_upload_data(struct intel_context * intel,const void * ptr,GLuint size,GLuint align,drm_intel_bo ** return_bo,GLuint * return_offset)532 void 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 
578 drm_intel_bo *
intel_bufferobj_source(struct intel_context * intel,struct intel_buffer_object * intel_obj,GLuint align,GLuint * offset)579 intel_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 
594 static void
intel_bufferobj_copy_subdata(struct gl_context * ctx,struct gl_buffer_object * src,struct gl_buffer_object * dst,GLintptr read_offset,GLintptr write_offset,GLsizeiptr size)595 intel_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 
658 static GLenum
intel_buffer_purgeable(drm_intel_bo * buffer)659 intel_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 
669 static GLenum
intel_buffer_object_purgeable(struct gl_context * ctx,struct gl_buffer_object * obj,GLenum option)670 intel_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 
693 static GLenum
intel_texture_object_purgeable(struct gl_context * ctx,struct gl_texture_object * obj,GLenum option)694 intel_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 
710 static GLenum
intel_render_object_purgeable(struct gl_context * ctx,struct gl_renderbuffer * obj,GLenum option)711 intel_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 
727 static GLenum
intel_buffer_unpurgeable(drm_intel_bo * buffer)728 intel_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 
739 static GLenum
intel_buffer_object_unpurgeable(struct gl_context * ctx,struct gl_buffer_object * obj,GLenum option)740 intel_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 
750 static GLenum
intel_texture_object_unpurgeable(struct gl_context * ctx,struct gl_texture_object * obj,GLenum option)751 intel_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 
767 static GLenum
intel_render_object_unpurgeable(struct gl_context * ctx,struct gl_renderbuffer * obj,GLenum option)768 intel_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 
784 void
intelInitBufferObjectFuncs(struct dd_function_table * functions)785 intelInitBufferObjectFuncs(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