[intel] Assert against conflicting relocation emits in bufmgr_fake.c
[mesa.git] / src / mesa / drivers / dri / common / texmem.c
index 4ed05219db93c397595d5ab1cdb6f860cf1a7864..b0e8c4c1c2824c871168bfbfd8862c21fd1b586b 100644 (file)
@@ -47,6 +47,7 @@
 #include "simple_list.h"
 #include "imports.h"
 #include "macros.h"
+#include "texformat.h"
 
 #include <assert.h>
 
@@ -64,11 +65,10 @@ static unsigned dummy_swap_counter;
  * \param n Value whose \f$\log_2\f$ is to be calculated
  */
 
-static unsigned
-driLog2( unsigned n )
+static GLuint
+driLog2( GLuint n )
 {
-   unsigned   log2;
-
+   GLuint log2;
 
    for ( log2 = 1 ; n > 1 ; log2++ ) {
       n >>= 1;
@@ -188,7 +188,7 @@ static void printLocalLRU( driTexHeap * heap, const char *callername  )
 static void printGlobalLRU( driTexHeap * heap, const char *callername )
 {
    drmTextureRegionPtr list = heap->global_regions;
-   int i, j;
+   unsigned int i, j;
 
    fprintf( stderr, "%s in %s:\nGlobal LRU, heap %d list %p:\n", 
            __FUNCTION__, callername, heap->heapId, (void *)list );
@@ -246,7 +246,6 @@ void driUpdateTextureLRU( driTextureObject * t )
 
 
       for (i = start ; i <= end ; i++) {
-        list[i].in_use = 1;
         list[i].age = heap->local_age;
 
         /* remove_from_list(i)
@@ -374,7 +373,7 @@ void driDestroyTextureObject( driTextureObject * t )
  * \param heap Heap whose state is to be updated
  * \param offset Byte offset in the heap that has been stolen
  * \param size Size, in bytes, of the stolen block
- * \param in_use Non-zero if the block is in-use by another context
+ * \param in_use Non-zero if the block is pinned/reserved by the kernel
  */
 
 static void driTexturesGone( driTexHeap * heap, int offset, int size, 
@@ -396,19 +395,13 @@ static void driTexturesGone( driTexHeap * heap, int offset, int size,
            driSwapOutTextureObject( t );
         }
         else {
-           if ( in_use && 
-                offset == t->memBlock->ofs && size == t->memBlock->size ) {
-              /* Matching placeholder already exists */
-              return;
-           } else {
-              driDestroyTextureObject( t );
-           }
+           driDestroyTextureObject( t );
         }
       }
    }
 
 
-   if ( in_use ) {
+   {
       t = (driTextureObject *) CALLOC( heap->texture_object_size );
       if ( t == NULL ) return;
 
@@ -417,9 +410,12 @@ static void driTexturesGone( driTexHeap * heap, int offset, int size,
         fprintf( stderr, "Couldn't alloc placeholder: heap %u sz %x ofs %x\n", heap->heapId,
                  (int)size, (int)offset );
         mmDumpMemInfo( heap->memory_heap );
+        FREE(t);
         return;
       }
       t->heap = heap;
+      if (in_use) 
+        t->reserved = 1; 
       insert_at_head( & heap->texture_objects, t );
    }
 }
@@ -482,6 +478,8 @@ void driAgeTextures( driTexHeap * heap )
 
 
 
+#define INDEX_ARRAY_SIZE 6 /* I'm not aware of driver with more than 2 heaps */
+
 /**
  * Allocate memory from a texture heap to hold a texture object.  This
  * routine will attempt to allocate memory for the texture from the heaps
@@ -533,35 +531,91 @@ driAllocateTexture( driTexHeap * const * heap_array, unsigned nr_heaps,
     */
 
    if ( t->memBlock == NULL ) {
-      for ( id = 0 ; (t->memBlock == NULL) && (id < nr_heaps) ; id++ ) {
-        heap = heap_array[ id ];
-        if ( t->totalSize <= heap->size ) { 
+      unsigned index[INDEX_ARRAY_SIZE];
+      unsigned nrGoodHeaps = 0;
 
-           for ( cursor = heap->texture_objects.prev, temp = cursor->prev;
-                 cursor != &heap->texture_objects ; 
-                 cursor = temp, temp = cursor->prev ) {
-              
-              /* The the LRU element.  If the texture is bound to one of
-               * the texture units, then we cannot kick it out.
-               */
-              if ( cursor->bound /* || cursor->reserved */ ) {
-                 continue;
-              }
+      /* Trying to avoid dynamic memory allocation. If you have more
+       * heaps, increase INDEX_ARRAY_SIZE. I'm not aware of any
+       * drivers with more than 2 tex heaps. */
+      assert( nr_heaps < INDEX_ARRAY_SIZE );
 
-              /* If this is a placeholder, there's no need to keep it */
-              if (cursor->tObj)
-                  driSwapOutTextureObject( cursor );
-              else
-                  driDestroyTextureObject( cursor );
+      /* Sort large enough heaps by duty. Insertion sort should be
+       * fast enough for such a short array. */
+      for ( id = 0 ; id < nr_heaps ; id++ ) {
+        heap = heap_array[ id ];
 
-              t->memBlock = mmAllocMem( heap->memory_heap, t->totalSize, 
-                                        heap->alignmentShift, 0 );
+        if ( heap != NULL && t->totalSize <= heap->size ) {
+           unsigned j;
 
-              if (t->memBlock)
+           for ( j = 0 ; j < nrGoodHeaps; j++ ) {
+              if ( heap->duty > heap_array[ index[ j ] ]->duty )
                  break;
            }
-        }     /* if ( t->totalSize <= heap->size ) ... */
+
+           if ( j < nrGoodHeaps ) {
+              memmove( &index[ j+1 ], &index[ j ],
+                       sizeof(index[ 0 ]) * (nrGoodHeaps - j) );
+           }
+
+           index[ j ] = id;
+
+           nrGoodHeaps++;
+        }
+      }
+
+      for ( id = 0 ; (t->memBlock == NULL) && (id < nrGoodHeaps) ; id++ ) {
+        heap = heap_array[ index[ id ] ];
+
+        for ( cursor = heap->texture_objects.prev, temp = cursor->prev;
+              cursor != &heap->texture_objects ; 
+              cursor = temp, temp = cursor->prev ) {
+              
+           /* The the LRU element.  If the texture is bound to one of
+            * the texture units, then we cannot kick it out.
+            */
+           if ( cursor->bound || cursor->reserved ) {
+              continue;
+           }
+
+           if ( cursor->memBlock )
+              heap->duty -= cursor->memBlock->size;
+
+           /* If this is a placeholder, there's no need to keep it */
+           if (cursor->tObj)
+              driSwapOutTextureObject( cursor );
+           else
+              driDestroyTextureObject( cursor );
+
+           t->memBlock = mmAllocMem( heap->memory_heap, t->totalSize, 
+                                     heap->alignmentShift, 0 );
+
+           if (t->memBlock)
+              break;
+        }
       }
+
+      /* Rebalance duties. If a heap kicked more data than its duty,
+       * then all other heaps get that amount multiplied with their
+       * relative weight added to their duty. The negative duty is
+       * reset to 0. In the end all heaps have a duty >= 0.
+       *
+       * CAUTION: we must not change the heap pointer here, because it
+       * is used below to update the texture object.
+       */
+      for ( id = 0 ; id < nr_heaps ; id++ )
+        if ( heap_array[ id ] != NULL && heap_array[ id ]->duty < 0) {
+           int duty = -heap_array[ id ]->duty;
+           double weight = heap_array[ id ]->weight;
+           unsigned j;
+
+           for ( j = 0 ; j < nr_heaps ; j++ )
+              if ( j != id && heap_array[ j ] != NULL ) {
+                 heap_array[ j ]->duty += (double) duty *
+                    heap_array[ j ]->weight / weight;
+              }
+
+           heap_array[ id ]->duty = 0;
+        }
    }
 
 
@@ -673,13 +727,16 @@ driCreateTextureHeap( unsigned heap_id, void * context, unsigned size,
         heap->destroy_texture_object = destroy_tex_obj;
 
         /* Force global heap init */
-        if (heap->global_age == 0)
+        if (heap->global_age[0] == 0)
             heap->local_age = ~0;
         else
             heap->local_age = 0;
 
         make_empty_list( & heap->texture_objects );
         driSetTextureSwapCounterLocation( heap, NULL );
+
+        heap->weight = heap->size;
+        heap->duty = 0;
       }
       else {
         FREE( heap );
@@ -889,7 +946,7 @@ get_max_size( unsigned nr_heaps,
     do { if ( max_sizes[v] != 0 ) { limits-> f = max_sizes[v]; } } while( 0 )
 
 #define SET_MAX_RECT(f,v) \
-    do { if ( max_sizes[v] != 0 ) { limits-> f = 1 << max_sizes[v]; } } while( 0 )
+    do { if ( max_sizes[v] != 0 ) { limits-> f = 1 << (max_sizes[v] - 1); } } while( 0 )
 
 
 /**
@@ -915,19 +972,22 @@ get_max_size( unsigned nr_heaps,
  *     For hardware that does not support mipmapping, this will be 1.
  * \param all_textures_one_heap True if the hardware requires that all
  *     textures be in a single texture heap for multitexturing.
+ * \param allow_larger_textures 0 conservative, 1 calculate limits
+ *     so at least one worst-case texture can fit, 2 just use hw limits.
  */
 
 void
 driCalculateMaxTextureLevels( driTexHeap * const * heaps,
                              unsigned nr_heaps,
                              struct gl_constants * limits,
-                             unsigned max_bytes_per_texel, 
+                             unsigned max_bytes_per_texel,
                              unsigned max_2D_size,
                              unsigned max_3D_size,
                              unsigned max_cube_size,
                              unsigned max_rect_size,
                              unsigned mipmaps_at_once,
-                             int all_textures_one_heap )
+                             int all_textures_one_heap,
+                             int allow_larger_textures )
 {
    struct maps_per_heap  max_textures[8];
    unsigned         i;
@@ -944,8 +1004,8 @@ driCalculateMaxTextureLevels( driTexHeap * const * heaps,
 
    mipmaps[0] = mipmaps_at_once;
    mipmaps[1] = mipmaps_at_once;
-   mipmaps[2] = 1;
-   mipmaps[3] = mipmaps_at_once;
+   mipmaps[2] = mipmaps_at_once;
+   mipmaps[3] = 1;
 
 
    /* Calculate the maximum number of texture levels in two passes.  The
@@ -956,18 +1016,22 @@ driCalculateMaxTextureLevels( driTexHeap * const * heaps,
     */
 
    for ( i = 0 ; i < 4 ; i++ ) {
-      if ( max_sizes[ i ] != 0 ) {
-        fill_in_maximums( heaps, nr_heaps, max_bytes_per_texel, 
+      if ( (allow_larger_textures != 2) && (max_sizes[ i ] != 0) ) {
+        fill_in_maximums( heaps, nr_heaps, max_bytes_per_texel,
                           max_sizes[ i ], mipmaps[ i ],
                           dimensions[ i ], faces[ i ],
                           max_textures );
 
-        max_sizes[ i ] = get_max_size( nr_heaps, 
-                                       limits->MaxTextureUnits,
+        max_sizes[ i ] = get_max_size( nr_heaps,
+                                       allow_larger_textures == 1 ?
+                                       1 : limits->MaxTextureUnits,
                                        max_sizes[ i ],
                                        all_textures_one_heap,
                                        max_textures );
       }
+      else if (max_sizes[ i ] != 0) {
+        max_sizes[ i ] += 1;
+      }
    }
 
    SET_MAX( MaxTextureLevels,        0 );
@@ -1082,13 +1146,13 @@ driValidateTextureHeaps( driTexHeap * const * texture_heaps,
       unsigned textures_in_heap = 0;
       unsigned blocks_in_mempool = 0;
       const driTexHeap * heap = texture_heaps[i];
-      const memHeap_t * p = heap->memory_heap;
+      const struct mem_block *p = heap->memory_heap;
 
       /* Check each texture object has a MemBlock, and is linked into
        * the correct heap.  
        *
        * Check the texobj base address corresponds to the MemBlock
-       * range.  Check the texobj size (recalculate???) fits within
+       * range.  Check the texobj size (recalculate?) fits within
        * the MemBlock.
        *
        * Count the number of texobj's using this heap.
@@ -1188,7 +1252,7 @@ driCalculateTextureFirstLastLevel( driTextureObject * t )
 {
    struct gl_texture_object * const tObj = t->tObj;
    const struct gl_texture_image * const baseImage =
-       tObj->Image[tObj->BaseLevel];
+       tObj->Image[0][tObj->BaseLevel];
 
    /* These must be signed values.  MinLod and MaxLod can be negative numbers,
     * and having firstLevel and lastLevel as signed prevents the need for
@@ -1233,3 +1297,51 @@ driCalculateTextureFirstLastLevel( driTextureObject * t )
    t->firstLevel = firstLevel;
    t->lastLevel = lastLevel;
 }
+
+
+
+
+/**
+ * \name DRI texture formats.  Pointers initialized to either the big- or
+ * little-endian Mesa formats.
+ */
+/*@{*/
+const struct gl_texture_format *_dri_texformat_rgba8888 = NULL;
+const struct gl_texture_format *_dri_texformat_argb8888 = NULL;
+const struct gl_texture_format *_dri_texformat_rgb565 = NULL;
+const struct gl_texture_format *_dri_texformat_argb4444 = NULL;
+const struct gl_texture_format *_dri_texformat_argb1555 = NULL;
+const struct gl_texture_format *_dri_texformat_al88 = NULL;
+const struct gl_texture_format *_dri_texformat_a8 = &_mesa_texformat_a8;
+const struct gl_texture_format *_dri_texformat_ci8 = &_mesa_texformat_ci8;
+const struct gl_texture_format *_dri_texformat_i8 = &_mesa_texformat_i8;
+const struct gl_texture_format *_dri_texformat_l8 = &_mesa_texformat_l8;
+/*@}*/
+
+
+/**
+ * Initialize little endian target, host byte order independent texture formats
+ */
+void
+driInitTextureFormats(void)
+{
+   const GLuint ui = 1;
+   const GLubyte littleEndian = *((const GLubyte *) &ui);
+
+   if (littleEndian) {
+      _dri_texformat_rgba8888  = &_mesa_texformat_rgba8888;
+      _dri_texformat_argb8888  = &_mesa_texformat_argb8888;
+      _dri_texformat_rgb565    = &_mesa_texformat_rgb565;
+      _dri_texformat_argb4444  = &_mesa_texformat_argb4444;
+      _dri_texformat_argb1555  = &_mesa_texformat_argb1555;
+      _dri_texformat_al88      = &_mesa_texformat_al88;
+   }
+   else {
+      _dri_texformat_rgba8888  = &_mesa_texformat_rgba8888_rev;
+      _dri_texformat_argb8888  = &_mesa_texformat_argb8888_rev;
+      _dri_texformat_rgb565    = &_mesa_texformat_rgb565_rev;
+      _dri_texformat_argb4444  = &_mesa_texformat_argb4444_rev;
+      _dri_texformat_argb1555  = &_mesa_texformat_argb1555_rev;
+      _dri_texformat_al88      = &_mesa_texformat_al88_rev;
+   }
+}