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