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