Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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.    free(intel_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.