Home | History | Annotate | Download | only in i915
      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
     48 intel_bufferobj_alloc_buffer(struct intel_context *intel,
     49 			     struct intel_buffer_object *intel_obj)
     50 {
     51    intel_obj->buffer = drm_intel_bo_alloc(intel->bufmgr, "bufferobj",
     52 					  intel_obj->Base.Size, 64);
     53 }
     54 
     55 static void
     56 release_buffer(struct intel_buffer_object *intel_obj)
     57 {
     58    drm_intel_bo_unreference(intel_obj->buffer);
     59    intel_obj->buffer = NULL;
     60    intel_obj->offset = 0;
     61    intel_obj->source = 0;
     62 }
     63 
     64 /**
     65  * There is some duplication between mesa's bufferobjects and our
     66  * bufmgr buffers.  Both have an integer handle and a hashtable to
     67  * lookup an opaque structure.  It would be nice if the handles and
     68  * internal structure where somehow shared.
     69  */
     70 static struct gl_buffer_object *
     71 intel_bufferobj_alloc(struct gl_context * ctx, GLuint name)
     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
     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
    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
    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
    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 *
    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
    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
    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 *
    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
    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 
    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 
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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