Merge branch 'mesa_7_5_branch'
[mesa.git] / src / mesa / drivers / dri / i965 / brw_wm_sampler_state.c
index 93d4cfc3a5f2d739b7599a049f3c3f637761727f..3fc18ff1f3a3cfbc2de60736a96bb59c90d52839 100644 (file)
@@ -34,7 +34,7 @@
 #include "brw_state.h"
 #include "brw_defines.h"
 
-#include "macros.h"
+#include "main/macros.h"
 
 
 
@@ -54,7 +54,7 @@ static GLuint translate_wrap_mode( GLenum wrap )
    case GL_REPEAT: 
       return BRW_TEXCOORDMODE_WRAP;
    case GL_CLAMP:  
-      return BRW_TEXCOORDMODE_CLAMP_BORDER; /* conform likes it this way */
+      return BRW_TEXCOORDMODE_CLAMP;
    case GL_CLAMP_TO_EDGE: 
       return BRW_TEXCOORDMODE_CLAMP; /* conform likes it this way */
    case GL_CLAMP_TO_BORDER: 
@@ -79,27 +79,44 @@ static GLint S_FIXED(GLfloat value, GLuint frac_bits)
 }
 
 
-static GLuint upload_default_color( struct brw_context *brw,
-                                   const GLfloat *color )
+static dri_bo *upload_default_color( struct brw_context *brw,
+                                    const GLfloat *color )
 {
    struct brw_sampler_default_color sdc;
 
    COPY_4V(sdc.color, color); 
    
-   return brw_cache_data( &brw->cache[BRW_SAMPLER_DEFAULT_COLOR], &sdc );
+   return brw_cache_data( &brw->cache, BRW_SAMPLER_DEFAULT_COLOR, &sdc,
+                         NULL, 0 );
 }
 
 
-/*
+struct wm_sampler_key {
+   int sampler_count;
+
+   struct wm_sampler_entry {
+      GLenum tex_target;
+      GLenum wrap_r, wrap_s, wrap_t;
+      float maxlod, minlod;
+      float lod_bias;
+      float max_aniso;
+      GLenum minfilter, magfilter;
+      GLenum comparemode, comparefunc;
+      dri_bo *sdc_bo;
+   } sampler[BRW_MAX_TEX_UNIT];
+};
+
+/**
+ * Sets the sampler state for a single unit based off of the sampler key
+ * entry.
  */
-static void brw_update_sampler_state( struct gl_texture_unit *texUnit,
-                                     struct gl_texture_object *texObj,
-                                     GLuint sdc_gs_offset,
-                                     struct brw_sampler_state *sampler)
-{   
+static void brw_update_sampler_state(struct wm_sampler_entry *key,
+                                    dri_bo *sdc_bo,
+                                    struct brw_sampler_state *sampler)
+{
    _mesa_memset(sampler, 0, sizeof(*sampler));
 
-   switch (texObj->MinFilter) {
+   switch (key->minfilter) {
    case GL_NEAREST:
       sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
       sampler->ss0.mip_filter = BRW_MIPFILTER_NONE;
@@ -130,17 +147,17 @@ static void brw_update_sampler_state( struct gl_texture_unit *texUnit,
 
    /* Set Anisotropy: 
     */
-   if ( texObj->MaxAnisotropy > 1.0 ) {
+   if (key->max_aniso > 1.0) {
       sampler->ss0.min_filter = BRW_MAPFILTER_ANISOTROPIC; 
       sampler->ss0.mag_filter = BRW_MAPFILTER_ANISOTROPIC;
 
-      if (texObj->MaxAnisotropy > 2.0) {
-        sampler->ss3.max_aniso = MAX2((texObj->MaxAnisotropy - 2) / 2,
+      if (key->max_aniso > 2.0) {
+        sampler->ss3.max_aniso = MIN2((key->max_aniso - 2) / 2,
                                       BRW_ANISORATIO_16);
       }
    }
    else {
-      switch (texObj->MagFilter) {
+      switch (key->magfilter) {
       case GL_NEAREST:
         sampler->ss0.mag_filter = BRW_MAPFILTER_NEAREST;
         break;
@@ -152,33 +169,45 @@ static void brw_update_sampler_state( struct gl_texture_unit *texUnit,
       }  
    }
 
-   sampler->ss1.r_wrap_mode = translate_wrap_mode(texObj->WrapR);
-   sampler->ss1.s_wrap_mode = translate_wrap_mode(texObj->WrapS);
-   sampler->ss1.t_wrap_mode = translate_wrap_mode(texObj->WrapT);
-
-   /* Fulsim complains if I don't do this.  Hardware doesn't mind:
-    */
-#if 0
-   if (texObj->Target == GL_TEXTURE_CUBE_MAP_ARB) {
+   if (key->tex_target == GL_TEXTURE_CUBE_MAP &&
+       (key->minfilter != GL_NEAREST || key->magfilter != GL_NEAREST)) {
+      /* If we're using anything but nearest sampling for a cube map, we
+       * need to set this wrap mode to avoid GPU lock-ups.
+       */
       sampler->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CUBE;
       sampler->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CUBE;
       sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CUBE;
    }
-#endif
+   else if (key->tex_target == GL_TEXTURE_1D) {
+      /* There's a bug in 1D texture sampling - it actually pays
+       * attention to the wrap_t value, though it should not.
+       * Override the wrap_t value here to GL_REPEAT to keep
+       * any nonexistent border pixels from floating in.
+       */
+      sampler->ss1.r_wrap_mode = translate_wrap_mode(key->wrap_r);
+      sampler->ss1.s_wrap_mode = translate_wrap_mode(key->wrap_s);
+      sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_WRAP;
+   }
+   else {
+      sampler->ss1.r_wrap_mode = translate_wrap_mode(key->wrap_r);
+      sampler->ss1.s_wrap_mode = translate_wrap_mode(key->wrap_s);
+      sampler->ss1.t_wrap_mode = translate_wrap_mode(key->wrap_t);
+   }
 
    /* Set shadow function: 
     */
-   if (texObj->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) {
+   if (key->comparemode == GL_COMPARE_R_TO_TEXTURE_ARB) {
       /* Shadowing is "enabled" by emitting a particular sampler
        * message (sample_c).  So need to recompile WM program when
        * shadow comparison is enabled on each/any texture unit.
        */
-      sampler->ss0.shadow_function = intel_translate_compare_func(texObj->CompareFunc);
+      sampler->ss0.shadow_function =
+        intel_translate_shadow_compare_func(key->comparefunc);
    }
 
    /* Set LOD bias: 
     */
-   sampler->ss0.lod_bias = S_FIXED(texUnit->LodBias + texObj->LodBias, 6);
+   sampler->ss0.lod_bias = S_FIXED(CLAMP(key->lod_bias, -16, 15), 6);
 
    sampler->ss0.lod_preclamp = 1; /* OpenGL mode */
    sampler->ss0.default_color_mode = 0; /* OpenGL/DX10 mode */
@@ -192,13 +221,68 @@ static void brw_update_sampler_state( struct gl_texture_unit *texUnit,
     */
    sampler->ss0.base_level = U_FIXED(0, 1);
 
-   sampler->ss1.max_lod = U_FIXED(MAX2(texObj->MaxLod, 0), 6);
-   sampler->ss1.min_lod = U_FIXED(MAX2(texObj->MinLod, 0), 6);
+   sampler->ss1.max_lod = U_FIXED(MIN2(MAX2(key->maxlod, 0), 13), 6);
+   sampler->ss1.min_lod = U_FIXED(MIN2(MAX2(key->minlod, 0), 13), 6);
    
-   sampler->ss2.default_color_pointer = sdc_gs_offset >> 5;
+   sampler->ss2.default_color_pointer = sdc_bo->offset >> 5; /* reloc */
 }
 
 
+/** Sets up the cache key for sampler state for all texture units */
+static void
+brw_wm_sampler_populate_key(struct brw_context *brw,
+                           struct wm_sampler_key *key)
+{
+   GLcontext *ctx = &brw->intel.ctx;
+   int unit;
+
+   memset(key, 0, sizeof(*key));
+
+   for (unit = 0; unit < BRW_MAX_TEX_UNIT; unit++) {
+      if (ctx->Texture.Unit[unit]._ReallyEnabled) {
+        struct wm_sampler_entry *entry = &key->sampler[unit];
+        struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+        struct gl_texture_object *texObj = texUnit->_Current;
+        struct intel_texture_object *intelObj = intel_texture_object(texObj);
+        struct gl_texture_image *firstImage =
+           texObj->Image[0][intelObj->firstLevel];
+
+         entry->tex_target = texObj->Target;
+
+        entry->wrap_r = texObj->WrapR;
+        entry->wrap_s = texObj->WrapS;
+        entry->wrap_t = texObj->WrapT;
+
+        entry->maxlod = texObj->MaxLod;
+        entry->minlod = texObj->MinLod;
+        entry->lod_bias = texUnit->LodBias + texObj->LodBias;
+        entry->max_aniso = texObj->MaxAnisotropy;
+        entry->minfilter = texObj->MinFilter;
+        entry->magfilter = texObj->MagFilter;
+        entry->comparemode = texObj->CompareMode;
+         entry->comparefunc = texObj->CompareFunc;
+
+        dri_bo_unreference(brw->wm.sdc_bo[unit]);
+        if (firstImage->_BaseFormat == GL_DEPTH_COMPONENT) {
+           float bordercolor[4] = {
+              texObj->BorderColor[0],
+              texObj->BorderColor[0],
+              texObj->BorderColor[0],
+              texObj->BorderColor[0]
+           };
+           /* GL specs that border color for depth textures is taken from the
+            * R channel, while the hardware uses A.  Spam R into all the
+            * channels for safety.
+            */
+           brw->wm.sdc_bo[unit] = upload_default_color(brw, bordercolor);
+        } else {
+           brw->wm.sdc_bo[unit] = upload_default_color(brw,
+                                                       texObj->BorderColor);
+        }
+        key->sampler_count = unit + 1;
+      }
+   }
+}
 
 /* All samplers must be uploaded in a single contiguous array, which
  * complicates various things.  However, this is still too confusing -
@@ -206,40 +290,62 @@ static void brw_update_sampler_state( struct gl_texture_unit *texUnit,
  */
 static void upload_wm_samplers( struct brw_context *brw )
 {
-   GLuint unit;
-   GLuint sampler_count = 0;
-
-   /* _NEW_TEXTURE */
-   for (unit = 0; unit < BRW_MAX_TEX_UNIT; unit++) {
-      if (brw->attribs.Texture->Unit[unit]._ReallyEnabled) {    
-        struct gl_texture_unit *texUnit = &brw->attribs.Texture->Unit[unit];
-        struct gl_texture_object *texObj = texUnit->_Current;
+   GLcontext *ctx = &brw->intel.ctx;
+   struct wm_sampler_key key;
+   int i;
 
-        GLuint sdc_gs_offset = upload_default_color(brw, texObj->BorderColor);
+   brw_wm_sampler_populate_key(brw, &key);
 
-        brw_update_sampler_state(texUnit,
-                                 texObj, 
-                                 sdc_gs_offset,
-                                 &brw->wm.sampler[unit]);
-
-        sampler_count = unit + 1;
-      }
-   }
-   
-   if (brw->wm.sampler_count != sampler_count) {
-      brw->wm.sampler_count = sampler_count;
+   if (brw->wm.sampler_count != key.sampler_count) {
+      brw->wm.sampler_count = key.sampler_count;
       brw->state.dirty.cache |= CACHE_NEW_SAMPLER;
    }
 
-   brw->wm.sampler_gs_offset = 0;
+   dri_bo_unreference(brw->wm.sampler_bo);
+   brw->wm.sampler_bo = NULL;
+   if (brw->wm.sampler_count == 0)
+      return;
 
-   if (brw->wm.sampler_count) 
-      brw->wm.sampler_gs_offset = 
-        brw_cache_data_sz(&brw->cache[BRW_SAMPLER],
-                          brw->wm.sampler,
-                          sizeof(struct brw_sampler_state) * brw->wm.sampler_count);
-}
+   brw->wm.sampler_bo = brw_search_cache(&brw->cache, BRW_SAMPLER,
+                                        &key, sizeof(key),
+                                        brw->wm.sdc_bo, key.sampler_count,
+                                        NULL);
+
+   /* If we didnt find it in the cache, compute the state and put it in the
+    * cache.
+    */
+   if (brw->wm.sampler_bo == NULL) {
+      struct brw_sampler_state sampler[BRW_MAX_TEX_UNIT];
 
+      memset(sampler, 0, sizeof(sampler));
+      for (i = 0; i < key.sampler_count; i++) {
+        if (brw->wm.sdc_bo[i] == NULL)
+           continue;
+
+        brw_update_sampler_state(&key.sampler[i], brw->wm.sdc_bo[i],
+                                 &sampler[i]);
+      }
+
+      brw->wm.sampler_bo = brw_upload_cache(&brw->cache, BRW_SAMPLER,
+                                           &key, sizeof(key),
+                                           brw->wm.sdc_bo, key.sampler_count,
+                                           &sampler, sizeof(sampler),
+                                           NULL, NULL);
+
+      /* Emit SDC relocations */
+      for (i = 0; i < BRW_MAX_TEX_UNIT; i++) {
+        if (!ctx->Texture.Unit[i]._ReallyEnabled)
+           continue;
+
+        dri_bo_emit_reloc(brw->wm.sampler_bo,
+                          I915_GEM_DOMAIN_SAMPLER, 0,
+                          0,
+                          i * sizeof(struct brw_sampler_state) +
+                          offsetof(struct brw_sampler_state, ss2),
+                          brw->wm.sdc_bo[i]);
+      }
+   }
+}
 
 const struct brw_tracked_state brw_wm_samplers = {
    .dirty = {
@@ -247,7 +353,7 @@ const struct brw_tracked_state brw_wm_samplers = {
       .brw = 0,
       .cache = 0
    },
-   .update = upload_wm_samplers
+   .prepare = upload_wm_samplers,
 };