Merge branch 'mesa_7_5_branch' into mesa_7_6_branch
authorBrian Paul <brianp@vmware.com>
Mon, 28 Sep 2009 15:59:59 +0000 (09:59 -0600)
committerBrian Paul <brianp@vmware.com>
Mon, 28 Sep 2009 15:59:59 +0000 (09:59 -0600)
1  2 
src/gallium/auxiliary/util/u_gen_mipmap.c
src/mesa/drivers/dri/intel/intel_buffer_objects.c
src/mesa/state_tracker/st_cb_texture.c

  #include "util/u_gen_mipmap.h"
  #include "util/u_simple_shaders.h"
  
 -#include "tgsi/tgsi_build.h"
 -#include "tgsi/tgsi_dump.h"
 -#include "tgsi/tgsi_parse.h"
 -
  #include "cso_cache/cso_context.h"
  
  
@@@ -1515,6 -1519,17 +1515,17 @@@ util_gen_mipmap(struct gen_mipmap_stat
     uint zslice = 0;
     uint offset;
  
+    /* The texture object should have room for the levels which we're
+     * about to generate.
+     */
+    assert(lastLevel <= pt->last_level);
+    /* If this fails, why are we here? */
+    assert(lastLevel > baseLevel);
+    assert(filter == PIPE_TEX_FILTER_LINEAR ||
+           filter == PIPE_TEX_FILTER_NEAREST);
     /* check if we can render in the texture's format */
     if (!screen->is_format_supported(screen, pt->format, PIPE_TEXTURE_2D,
                                      PIPE_TEXTURE_USAGE_RENDER_TARGET, 0)) {
  
  #include "main/imports.h"
  #include "main/mtypes.h"
 +#include "main/macros.h"
  #include "main/bufferobj.h"
  
  #include "intel_context.h"
 +#include "intel_blit.h"
  #include "intel_buffer_objects.h"
  #include "intel_batchbuffer.h"
  #include "intel_regions.h"
  
 +static GLboolean
 +intel_bufferobj_unmap(GLcontext * ctx,
 +                      GLenum target, struct gl_buffer_object *obj);
  
  /** Allocates a new dri_bo to store the data for the buffer object. */
  static void
@@@ -105,13 -100,7 +105,13 @@@ intel_bufferobj_free(GLcontext * ctx, s
     struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
  
     assert(intel_obj);
 -   assert(!obj->Pointer); /* Mesa should have unmapped it */
 +
 +   /* Buffer objects are automatically unmapped when deleting according
 +    * to the spec, but Mesa doesn't do UnmapBuffer for us at context destroy
 +    * (though it does if you call glDeleteBuffers)
 +    */
 +   if (obj->Pointer)
 +      intel_bufferobj_unmap(ctx, 0, obj);
  
     _mesa_free(intel_obj->sys_buffer);
     if (intel_obj->region) {
   * Allocate space for and store data in a buffer object.  Any data that was
   * previously stored in the buffer object is lost.  If data is NULL,
   * memory will be allocated, but no copy will occur.
 - * Called via glBufferDataARB().
 + * Called via ctx->Driver.BufferData().
 + * \return GL_TRUE for success, GL_FALSE if out of memory
   */
 -static void
 +static GLboolean
  intel_bufferobj_data(GLcontext * ctx,
                       GLenum target,
                       GLsizeiptrARB size,
         if (intel_obj->sys_buffer != NULL) {
            if (data != NULL)
               memcpy(intel_obj->sys_buffer, data, size);
 -          return;
 +          return GL_TRUE;
         }
        }
  #endif
        intel_bufferobj_alloc_buffer(intel, intel_obj);
 +      if (!intel_obj->buffer)
 +         return GL_FALSE;
  
        if (data != NULL)
         dri_bo_subdata(intel_obj->buffer, 0, size, data);
     }
 +
 +   return GL_TRUE;
  }
  
  
@@@ -207,12 -191,8 +207,12 @@@ intel_bufferobj_subdata(GLcontext * ctx
  
     if (intel_obj->sys_buffer)
        memcpy((char *)intel_obj->sys_buffer + offset, data, size);
 -   else
 +   else {
 +      /* Flush any existing batchbuffer that might reference this data. */
 +      intelFlush(ctx);
 +
        dri_bo_subdata(intel_obj->buffer, offset, size, data);
 +   }
  }
  
  
@@@ -229,7 -209,10 +229,10 @@@ intel_bufferobj_get_subdata(GLcontext 
     struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
  
     assert(intel_obj);
-    dri_bo_get_subdata(intel_obj->buffer, offset, size, data);
+    if (intel_obj->sys_buffer)
+       memcpy(data, (char *)intel_obj->sys_buffer + offset, size);
+    else
+       dri_bo_get_subdata(intel_obj->buffer, offset, size, data);
  }
  
  
@@@ -254,11 -237,6 +257,11 @@@ intel_bufferobj_map(GLcontext * ctx
        return obj->Pointer;
     }
  
 +   /* Flush any existing batchbuffer that might have written to this
 +    * buffer.
 +    */
 +   intelFlush(ctx);
 +
     if (intel_obj->region)
        intel_bufferobj_cow(intel, intel_obj);
  
     }
  
     obj->Pointer = intel_obj->buffer->virtual;
 +   obj->Length = obj->Size;
 +   obj->Offset = 0;
 +
     return obj->Pointer;
  }
  
 +/**
 + * Called via glMapBufferRange().
 + *
 + * The goal of this extension is to allow apps to accumulate their rendering
 + * at the same time as they accumulate their buffer object.  Without it,
 + * you'd end up blocking on execution of rendering every time you mapped
 + * the buffer to put new data in.
 + *
 + * We support it in 3 ways: If unsynchronized, then don't bother
 + * flushing the batchbuffer before mapping the buffer, which can save blocking
 + * in many cases.  If we would still block, and they allow the whole buffer
 + * to be invalidated, then just allocate a new buffer to replace the old one.
 + * If not, and we'd block, and they allow the subrange of the buffer to be
 + * invalidated, then we can make a new little BO, let them write into that,
 + * and blit it into the real BO at unmap time.
 + */
 +static void *
 +intel_bufferobj_map_range(GLcontext * ctx,
 +                        GLenum target, GLintptr offset, GLsizeiptr length,
 +                        GLbitfield access, struct gl_buffer_object *obj)
 +{
 +   struct intel_context *intel = intel_context(ctx);
 +   struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
 +
 +   assert(intel_obj);
 +
 +   /* _mesa_MapBufferRange (GL entrypoint) sets these, but the vbo module also
 +    * internally uses our functions directly.
 +    */
 +   obj->Offset = offset;
 +   obj->Length = length;
 +   obj->AccessFlags = access;
 +
 +   if (intel_obj->sys_buffer) {
 +      obj->Pointer = intel_obj->sys_buffer + offset;
 +      return obj->Pointer;
 +   }
 +
 +   if (intel_obj->region)
 +      intel_bufferobj_cow(intel, intel_obj);
 +
 +   /* If the mapping is synchronized with other GL operations, flush
 +    * the batchbuffer so that GEM knows about the buffer access for later
 +    * syncing.
 +    */
 +   if (!(access & GL_MAP_UNSYNCHRONIZED_BIT))
 +      intelFlush(ctx);
 +
 +   if (intel_obj->buffer == NULL) {
 +      obj->Pointer = NULL;
 +      return NULL;
 +   }
 +
 +   /* If the user doesn't care about existing buffer contents and mapping
 +    * would cause us to block, then throw out the old buffer.
 +    */
 +   if (!(access & GL_MAP_UNSYNCHRONIZED_BIT) &&
 +       (access & GL_MAP_INVALIDATE_BUFFER_BIT) &&
 +       drm_intel_bo_busy(intel_obj->buffer)) {
 +      drm_intel_bo_unreference(intel_obj->buffer);
 +      intel_obj->buffer = dri_bo_alloc(intel->bufmgr, "bufferobj",
 +                                     intel_obj->Base.Size, 64);
 +   }
 +
 +   /* If the user is mapping a range of an active buffer object but
 +    * doesn't require the current contents of that range, make a new
 +    * BO, and we'll copy what they put in there out at unmap or
 +    * FlushRange time.
 +    */
 +   if ((access & GL_MAP_INVALIDATE_RANGE_BIT) &&
 +       drm_intel_bo_busy(intel_obj->buffer)) {
 +      if (access & GL_MAP_FLUSH_EXPLICIT_BIT) {
 +       intel_obj->range_map_buffer = _mesa_malloc(length);
 +       obj->Pointer = intel_obj->range_map_buffer;
 +      } else {
 +       intel_obj->range_map_bo = drm_intel_bo_alloc(intel->bufmgr,
 +                                                    "range map",
 +                                                    length, 64);
 +       if (!(access & GL_MAP_READ_BIT) &&
 +           intel->intelScreen->kernel_exec_fencing) {
 +          drm_intel_gem_bo_map_gtt(intel_obj->range_map_bo);
 +          intel_obj->mapped_gtt = GL_TRUE;
 +       } else {
 +          drm_intel_bo_map(intel_obj->range_map_bo,
 +                           (access & GL_MAP_WRITE_BIT) != 0);
 +          intel_obj->mapped_gtt = GL_FALSE;
 +       }
 +       obj->Pointer = intel_obj->range_map_bo->virtual;
 +      }
 +      return obj->Pointer;
 +   }
 +
 +   if (!(access & GL_MAP_READ_BIT) &&
 +       intel->intelScreen->kernel_exec_fencing) {
 +      drm_intel_gem_bo_map_gtt(intel_obj->buffer);
 +      intel_obj->mapped_gtt = GL_TRUE;
 +   } else {
 +      drm_intel_bo_map(intel_obj->buffer, (access & GL_MAP_WRITE_BIT) != 0);
 +      intel_obj->mapped_gtt = GL_FALSE;
 +   }
 +
 +   obj->Pointer = intel_obj->buffer->virtual + offset;
 +   return obj->Pointer;
 +}
 +
 +/* Ideally we'd use a BO to avoid taking up cache space for the temporary
 + * data, but FlushMappedBufferRange may be followed by further writes to
 + * the pointer, so we would have to re-map after emitting our blit, which
 + * would defeat the point.
 + */
 +static void
 +intel_bufferobj_flush_mapped_range(GLcontext *ctx, GLenum target,
 +                                 GLintptr offset, GLsizeiptr length,
 +                                 struct gl_buffer_object *obj)
 +{
 +   struct intel_context *intel = intel_context(ctx);
 +   struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
 +   drm_intel_bo *temp_bo;
 +
 +   /* Unless we're in the range map using a temporary system buffer,
 +    * there's no work to do.
 +    */
 +   if (intel_obj->range_map_buffer == NULL)
 +      return;
 +
 +   temp_bo = drm_intel_bo_alloc(intel->bufmgr, "range map flush", length, 64);
 +
 +   drm_intel_bo_subdata(temp_bo, 0, length, intel_obj->range_map_buffer);
 +
 +   intel_emit_linear_blit(intel,
 +                        intel_obj->buffer, obj->Offset + offset,
 +                        temp_bo, 0,
 +                        length);
 +
 +   drm_intel_bo_unreference(temp_bo);
 +}
 +
  
  /**
 - * Called via glMapBufferARB().
 + * Called via glUnmapBuffer().
   */
  static GLboolean
  intel_bufferobj_unmap(GLcontext * ctx,
                        GLenum target, struct gl_buffer_object *obj)
  {
 +   struct intel_context *intel = intel_context(ctx);
     struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
  
     assert(intel_obj);
 +   assert(obj->Pointer);
     if (intel_obj->sys_buffer != NULL) {
 -      assert(obj->Pointer);
 -      obj->Pointer = NULL;
 +      /* always keep the mapping around. */
 +   } else if (intel_obj->range_map_buffer != NULL) {
 +      /* Since we've emitted some blits to buffers that will (likely) be used
 +       * in rendering operations in other cache domains in this batch, emit a
 +       * flush.  Once again, we wish for a domain tracker in libdrm to cover
 +       * usage inside of a batchbuffer.
 +       */
 +      intel_batchbuffer_emit_mi_flush(intel->batch);
 +      free(intel_obj->range_map_buffer);
 +      intel_obj->range_map_buffer = NULL;
 +   } else if (intel_obj->range_map_bo != NULL) {
 +      if (intel_obj->mapped_gtt) {
 +       drm_intel_gem_bo_unmap_gtt(intel_obj->range_map_bo);
 +      } else {
 +       drm_intel_bo_unmap(intel_obj->range_map_bo);
 +      }
 +
 +      intel_emit_linear_blit(intel,
 +                           intel_obj->buffer, obj->Offset,
 +                           intel_obj->range_map_bo, 0,
 +                           obj->Length);
 +
 +      /* Since we've emitted some blits to buffers that will (likely) be used
 +       * in rendering operations in other cache domains in this batch, emit a
 +       * flush.  Once again, we wish for a domain tracker in libdrm to cover
 +       * usage inside of a batchbuffer.
 +       */
 +      intel_batchbuffer_emit_mi_flush(intel->batch);
 +
 +      drm_intel_bo_unreference(intel_obj->range_map_bo);
 +      intel_obj->range_map_bo = NULL;
     } else if (intel_obj->buffer != NULL) {
 -      assert(obj->Pointer);
        if (intel_obj->mapped_gtt) {
         drm_intel_gem_bo_unmap_gtt(intel_obj->buffer);
        } else {
         drm_intel_bo_unmap(intel_obj->buffer);
        }
 -      obj->Pointer = NULL;
     }
 +   obj->Pointer = NULL;
 +   obj->Offset = 0;
 +   obj->Length = 0;
 +
     return GL_TRUE;
  }
  
@@@ -492,94 -297,30 +495,94 @@@ intel_bufferobj_buffer(struct intel_con
     }
  
     if (intel_obj->buffer == NULL) {
 +      void *sys_buffer = intel_obj->sys_buffer;
 +
 +      /* only one of buffer and sys_buffer could be non-NULL */
        intel_bufferobj_alloc_buffer(intel, intel_obj);
 +      intel_obj->sys_buffer = NULL;
 +
        intel_bufferobj_subdata(&intel->ctx,
                              GL_ARRAY_BUFFER_ARB,
                              0,
                              intel_obj->Base.Size,
 -                            intel_obj->sys_buffer,
 +                            sys_buffer,
                              &intel_obj->Base);
 -      _mesa_free(intel_obj->sys_buffer);
 +      _mesa_free(sys_buffer);
        intel_obj->sys_buffer = NULL;
     }
  
     return intel_obj->buffer;
  }
  
 +static void
 +intel_bufferobj_copy_subdata(GLcontext *ctx,
 +                           struct gl_buffer_object *src,
 +                           struct gl_buffer_object *dst,
 +                           GLintptr read_offset, GLintptr write_offset,
 +                           GLsizeiptr size)
 +{
 +   struct intel_context *intel = intel_context(ctx);
 +   struct intel_buffer_object *intel_src = intel_buffer_object(src);
 +   struct intel_buffer_object *intel_dst = intel_buffer_object(dst);
 +   drm_intel_bo *src_bo, *dst_bo;
 +
 +   if (size == 0)
 +      return;
 +
 +   /* If we're in system memory, just map and memcpy. */
 +   if (intel_src->sys_buffer || intel_dst->sys_buffer) {
 +      /* The same buffer may be used, but note that regions copied may
 +       * not overlap.
 +       */
 +      if (src == dst) {
 +       char *ptr = intel_bufferobj_map(ctx, GL_COPY_WRITE_BUFFER,
 +                                       GL_READ_WRITE, dst);
 +       memcpy(ptr + write_offset, ptr + read_offset, size);
 +       intel_bufferobj_unmap(ctx, GL_COPY_WRITE_BUFFER, dst);
 +      } else {
 +       const char *src_ptr;
 +       char *dst_ptr;
 +
 +       src_ptr =  intel_bufferobj_map(ctx, GL_COPY_READ_BUFFER,
 +                                      GL_READ_ONLY, src);
 +       dst_ptr =  intel_bufferobj_map(ctx, GL_COPY_WRITE_BUFFER,
 +                                      GL_WRITE_ONLY, dst);
 +
 +       memcpy(dst_ptr + write_offset, src_ptr + read_offset, size);
 +
 +       intel_bufferobj_unmap(ctx, GL_COPY_READ_BUFFER, src);
 +       intel_bufferobj_unmap(ctx, GL_COPY_WRITE_BUFFER, dst);
 +      }
 +   }
 +
 +   /* Otherwise, we have real BOs, so blit them. */
 +
 +   dst_bo = intel_bufferobj_buffer(intel, intel_dst, INTEL_WRITE_PART);
 +   src_bo = intel_bufferobj_buffer(intel, intel_src, INTEL_READ);
 +
 +   intel_emit_linear_blit(intel,
 +                        dst_bo, write_offset,
 +                        src_bo, read_offset, size);
 +
 +   /* Since we've emitted some blits to buffers that will (likely) be used
 +    * in rendering operations in other cache domains in this batch, emit a
 +    * flush.  Once again, we wish for a domain tracker in libdrm to cover
 +    * usage inside of a batchbuffer.
 +    */
 +   intel_batchbuffer_emit_mi_flush(intel->batch);
 +}
 +
  void
 -intel_bufferobj_init(struct intel_context *intel)
 +intelInitBufferObjectFuncs(struct dd_function_table *functions)
  {
 -   GLcontext *ctx = &intel->ctx;
 -
 -   ctx->Driver.NewBufferObject = intel_bufferobj_alloc;
 -   ctx->Driver.DeleteBuffer = intel_bufferobj_free;
 -   ctx->Driver.BufferData = intel_bufferobj_data;
 -   ctx->Driver.BufferSubData = intel_bufferobj_subdata;
 -   ctx->Driver.GetBufferSubData = intel_bufferobj_get_subdata;
 -   ctx->Driver.MapBuffer = intel_bufferobj_map;
 -   ctx->Driver.UnmapBuffer = intel_bufferobj_unmap;
 +   functions->NewBufferObject = intel_bufferobj_alloc;
 +   functions->DeleteBuffer = intel_bufferobj_free;
 +   functions->BufferData = intel_bufferobj_data;
 +   functions->BufferSubData = intel_bufferobj_subdata;
 +   functions->GetBufferSubData = intel_bufferobj_get_subdata;
 +   functions->MapBuffer = intel_bufferobj_map;
 +   functions->MapBufferRange = intel_bufferobj_map_range;
 +   functions->FlushMappedBufferRange = intel_bufferobj_flush_mapped_range;
 +   functions->UnmapBuffer = intel_bufferobj_unmap;
 +   functions->CopyBufferSubData = intel_bufferobj_copy_subdata;
  }
@@@ -60,7 -60,6 +60,7 @@@
  #include "util/u_tile.h"
  #include "util/u_blit.h"
  #include "util/u_surface.h"
 +#include "util/u_math.h"
  
  
  #define DBG if (0) printf
@@@ -239,6 -238,16 +239,6 @@@ do_memcpy(void *dest, const void *src, 
  }
  
  
 -static INLINE unsigned
 -logbase2(unsigned n)
 -{
 -   unsigned log2 = 0;
 -   while (n >>= 1)
 -      ++log2;
 -   return log2;
 -}
 -
 -
  /**
   * Return default texture usage bitmask for the given texture format.
   */
@@@ -332,9 -341,9 +332,9 @@@ guess_and_alloc_texture(struct st_conte
        lastLevel = firstLevel;
     }
     else {
 -      GLuint l2width = logbase2(width);
 -      GLuint l2height = logbase2(height);
 -      GLuint l2depth = logbase2(depth);
 +      GLuint l2width = util_logbase2(width);
 +      GLuint l2height = util_logbase2(height);
 +      GLuint l2depth = util_logbase2(depth);
        lastLevel = firstLevel + MAX2(MAX2(l2width, l2height), l2depth);
     }
  
@@@ -524,12 -533,6 +524,12 @@@ st_TexImage(GLcontext * ctx
     DBG("%s target %s level %d %dx%dx%d border %d\n", __FUNCTION__,
         _mesa_lookup_enum_by_nr(target), level, width, height, depth, border);
  
 +   /* switch to "normal" */
 +   if (stObj->surface_based) {
 +      _mesa_clear_texture_object(ctx, texObj);
 +      stObj->surface_based = GL_FALSE;
 +   }
 +
     /* gallium does not support texture borders, strip it off */
     if (border) {
        strip_texture_border(border, &width, &height, &depth, unpack, &unpackNB);
@@@ -879,7 -882,7 +879,7 @@@ decompress_with_blit(GLcontext * ctx, G
                                             PIPE_TRANSFER_READ,
                                             0, 0, width, height);
  
 -   pixels = _mesa_map_readpix_pbo(ctx, &ctx->Pack, pixels);
 +   pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels);
  
     /* copy/pack data into user buffer */
     if (st_equal_formats(stImage->pt->format, format, type)) {
        }
     }
  
 -   _mesa_unmap_readpix_pbo(ctx, &ctx->Pack);
 +   _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
  
     /* destroy the temp / dest surface */
     util_destroy_rgba_surface(dst_texture, dst_surface);
@@@ -1705,53 -1708,6 +1705,6 @@@ st_CopyTexSubImage3D(GLcontext * ctx, G
  }
  
  
- /**
-  * Compute which mipmap levels that really need to be sent to the hardware.
-  * This depends on the base image size, GL_TEXTURE_MIN_LOD,
-  * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
-  */
- static void
- calculate_first_last_level(struct st_texture_object *stObj)
- {
-    struct gl_texture_object *tObj = &stObj->base;
-    /* These must be signed values.  MinLod and MaxLod can be negative numbers,
-     * and having firstLevel and lastLevel as signed prevents the need for
-     * extra sign checks.
-     */
-    GLint firstLevel;
-    GLint lastLevel;
-    /* Yes, this looks overly complicated, but it's all needed.
-     */
-    switch (tObj->Target) {
-    case GL_TEXTURE_1D:
-    case GL_TEXTURE_2D:
-    case GL_TEXTURE_3D:
-    case GL_TEXTURE_CUBE_MAP:
-       if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) {
-          /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL.
-           */
-          firstLevel = lastLevel = tObj->BaseLevel;
-       }
-       else {
-          firstLevel = 0;
-          lastLevel = MIN2(tObj->MaxLevel,
-                           (int) tObj->Image[0][tObj->BaseLevel]->WidthLog2);
-       }
-       break;
-    case GL_TEXTURE_RECTANGLE_NV:
-    case GL_TEXTURE_4D_SGIS:
-       firstLevel = lastLevel = 0;
-       break;
-    default:
-       return;
-    }
-    stObj->lastLevel = lastLevel;
- }
  static void
  copy_image_data_to_texture(struct st_context *st,
                           struct st_texture_object *stObj,
@@@ -1815,13 -1771,16 +1768,16 @@@ st_finalize_texture(GLcontext *ctx
  
     *needFlush = GL_FALSE;
  
-    /* We know/require this is true by now: 
-     */
-    assert(stObj->base._Complete);
+    if (stObj->base._Complete) {
+       /* The texture is complete and we know exactly how many mipmap levels
+        * are present/needed.  This is conditional because we may be called
+        * from the st_generate_mipmap() function when the texture object is
+        * incomplete.  In that case, we'll have set stObj->lastLevel before
+        * we get here.
+        */
+       stObj->lastLevel = stObj->base._MaxLevel - stObj->base.BaseLevel;
+    }
  
-    /* What levels must the texture include at a minimum?
-     */
-    calculate_first_last_level(stObj);
     firstImage = st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]);
  
     /* If both firstImage and stObj point to a texture which can contain