glsl: fix crash in loop analysis when some controls can't be determined
[mesa.git] / src / gallium / drivers / i965 / brw_wm_sampler_state.c
index a8993f931207411c35805656ca041c810ef81db4..8406a1a9e208c5d1f4420a9bc798d71b4150a93f 100644 (file)
   *   Keith Whitwell <keith@tungstengraphics.com>
   */
                    
+#include "util/u_math.h"
+#include "util/u_format.h"
 
 #include "brw_context.h"
 #include "brw_state.h"
 #include "brw_defines.h"
+#include "brw_resource.h"
 
 
 /* Samplers aren't strictly wm state from the hardware's perspective,
 
 
 
-/* The brw (and related graphics cores) do not support GL_CLAMP.  The
- * Intel drivers for "other operating systems" implement GL_CLAMP as
- * GL_CLAMP_TO_EDGE, so the same is done here.
- */
-static GLuint translate_wrap_mode( GLenum wrap )
-{
-   switch( wrap ) {
-   case GL_REPEAT: 
-      return BRW_TEXCOORDMODE_WRAP;
-   case GL_CLAMP:  
-      return BRW_TEXCOORDMODE_CLAMP;
-   case GL_CLAMP_TO_EDGE: 
-      return BRW_TEXCOORDMODE_CLAMP; /* conform likes it this way */
-   case GL_CLAMP_TO_BORDER: 
-      return BRW_TEXCOORDMODE_CLAMP_BORDER;
-   case GL_MIRRORED_REPEAT: 
-      return BRW_TEXCOORDMODE_MIRROR;
-   default: 
-      return BRW_TEXCOORDMODE_WRAP;
-   }
-}
-
-
-static GLuint U_FIXED(GLfloat value, GLuint frac_bits)
-{
-   value *= (1<<frac_bits);
-   return value < 0 ? 0 : value;
-}
-
-static GLint S_FIXED(GLfloat value, GLuint frac_bits)
-{
-   return value * (1<<frac_bits);
-}
-
-
-static struct brw_winsys_buffer *upload_default_color( struct brw_context *brw,
-                                    const GLfloat *color )
+static enum pipe_error
+upload_default_color( struct brw_context *brw,
+                     const GLfloat *color,
+                      struct brw_winsys_buffer **bo_out )
 {
    struct brw_sampler_default_color sdc;
+   enum pipe_error ret;
 
    COPY_4V(sdc.color, color); 
    
-   return brw_cache_data( &brw->cache, BRW_SAMPLER_DEFAULT_COLOR, &sdc,
-                         NULL, 0 );
+   ret = brw_cache_data( &brw->cache, BRW_SAMPLER_DEFAULT_COLOR, &sdc,
+                         NULL, 0, bo_out );
+   if (ret)
+      return ret;
+
+   return PIPE_OK;
 }
 
 
 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;
-      struct brw_winsys_buffer *sdc_bo;
-
-      /** If target is cubemap, take context setting.
-       */
-      GLboolean seamless_cube_map;
-   } sampler[BRW_MAX_TEX_UNIT];
+   struct brw_sampler_state 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 wm_sampler_entry *key,
-                                    struct brw_winsys_buffer *sdc_bo,
-                                    struct brw_sampler_state *sampler)
-{
-   _mesa_memset(sampler, 0, sizeof(*sampler));
-
-   switch (key->minfilter) {
-   case GL_NEAREST:
-      sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
-      sampler->ss0.mip_filter = BRW_MIPFILTER_NONE;
-      break;
-   case GL_LINEAR:
-      sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
-      sampler->ss0.mip_filter = BRW_MIPFILTER_NONE;
-      break;
-   case GL_NEAREST_MIPMAP_NEAREST:
-      sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
-      sampler->ss0.mip_filter = BRW_MIPFILTER_NEAREST;
-      break;
-   case GL_LINEAR_MIPMAP_NEAREST:
-      sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
-      sampler->ss0.mip_filter = BRW_MIPFILTER_NEAREST;
-      break;
-   case GL_NEAREST_MIPMAP_LINEAR:
-      sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
-      sampler->ss0.mip_filter = BRW_MIPFILTER_LINEAR;
-      break;
-   case GL_LINEAR_MIPMAP_LINEAR:
-      sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
-      sampler->ss0.mip_filter = BRW_MIPFILTER_LINEAR;
-      break;
-   default:
-      break;
-   }
 
-   /* Set Anisotropy: 
-    */
-   if (key->max_aniso > 1.0) {
-      sampler->ss0.min_filter = BRW_MAPFILTER_ANISOTROPIC; 
-      sampler->ss0.mag_filter = BRW_MAPFILTER_ANISOTROPIC;
+/** 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)
+{
+   int i;
 
-      if (key->max_aniso > 2.0) {
-        sampler->ss3.max_aniso = MIN2((key->max_aniso - 2) / 2,
-                                      BRW_ANISORATIO_16);
-      }
-   }
-   else {
-      switch (key->magfilter) {
-      case GL_NEAREST:
-        sampler->ss0.mag_filter = BRW_MAPFILTER_NEAREST;
-        break;
-      case GL_LINEAR:
-        sampler->ss0.mag_filter = BRW_MAPFILTER_LINEAR;
-        break;
-      default:
-        break;
-      }  
-   }
+   memset(key, 0, sizeof(*key));
 
-   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);
+   key->sampler_count = MIN2(brw->curr.num_fragment_sampler_views,
+                           brw->curr.num_samplers);
 
-   /* Cube-maps on 965 and later must use the same wrap mode for all 3
-    * coordinate dimensions.  Futher, only CUBE and CLAMP are valid.
-    */
-   if (key->tex_target == GL_TEXTURE_CUBE_MAP) {
-      if (key->seamless_cube_map &&
-         (key->minfilter != GL_NEAREST || key->magfilter != GL_NEAREST)) {
-        sampler->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CUBE;
-        sampler->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CUBE;
-        sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CUBE;
-      } else {
-        sampler->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
-        sampler->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
-        sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
-      }
-   } 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.t_wrap_mode = BRW_TEXCOORDMODE_WRAP;
-   }
+   for (i = 0; i < key->sampler_count; i++) {
+      const struct brw_texture *tex = brw_texture(brw->curr.fragment_sampler_views[i]->texture);
+      const struct brw_sampler *sampler = brw->curr.sampler[i];
+      struct brw_sampler_state *entry = &key->sampler[i];
 
+      entry->ss0 = sampler->ss0;
+      entry->ss1 = sampler->ss1;
+      entry->ss2.default_color_pointer = 0; /* reloc */
+      entry->ss3 = sampler->ss3;
 
-   /* Set shadow function: 
-    */
-   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.
+      /* Cube-maps on 965 and later must use the same wrap mode for all 3
+       * coordinate dimensions.  Futher, only CUBE and CLAMP are valid.
        */
-      sampler->ss0.shadow_function =
-        intel_translate_shadow_compare_func(key->comparefunc);
+      if (tex->b.b.target == PIPE_TEXTURE_CUBE) {
+        if (FALSE &&
+            (sampler->ss0.min_filter != BRW_MAPFILTER_NEAREST || 
+             sampler->ss0.mag_filter != BRW_MAPFILTER_NEAREST)) {
+           entry->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CUBE;
+           entry->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CUBE;
+           entry->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CUBE;
+        } else {
+           entry->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
+           entry->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
+           entry->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
+        }
+      } else if (tex->b.b.target == PIPE_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.
+         */
+        entry->ss1.t_wrap_mode = BRW_TEXCOORDMODE_WRAP;
+      }
    }
-
-   /* Set LOD bias: 
-    */
-   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 */
-
-   /* Set BaseMipLevel, MaxLOD, MinLOD: 
-    *
-    * XXX: I don't think that using firstLevel, lastLevel works,
-    * because we always setup the surface state as if firstLevel ==
-    * level zero.  Probably have to subtract firstLevel from each of
-    * these:
-    */
-   sampler->ss0.base_level = U_FIXED(0, 1);
-
-   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_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)
+static enum pipe_error
+brw_wm_sampler_update_default_colors(struct brw_context *brw)
 {
-   int unit;
-
-   memset(key, 0, sizeof(*key));
+   enum pipe_error ret;
+   int nr = MIN2(brw->curr.num_fragment_sampler_views,
+                brw->curr.num_samplers);
+   int i;
 
-   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->seamless_cube_map = (texObj->Target == GL_TEXTURE_CUBE_MAP)
-           ? ctx->Texture.CubeMapSeamless : GL_FALSE;
-
-        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;
-
-        brw->sws->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;
+   for (i = 0; i < nr; i++) {
+      const struct brw_texture *tex = brw_texture(brw->curr.fragment_sampler_views[i]->texture);
+      const struct brw_sampler *sampler = brw->curr.sampler[i];
+      const float *bc;
+      float bordercolor[4] = {
+         sampler->border_color[0],
+         sampler->border_color[0],
+         sampler->border_color[0],
+         sampler->border_color[0]
+      };
+      
+      if (util_format_is_depth_or_stencil(tex->b.b.format)) {
+         bc = bordercolor;
       }
+      else {
+         bc = sampler->border_color;
+      }
+
+      /* 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.
+       */
+      ret = upload_default_color(brw, 
+                                 bc,
+                                 &brw->wm.sdc_bo[i]);
+      if (ret) 
+         return ret;
    }
+
+   return PIPE_OK;
 }
 
-/* All samplers must be uploaded in a single contiguous array, which
- * complicates various things.  However, this is still too confusing -
- * FIXME: simplify all the different new texture state flags.
+
+
+/* All samplers must be uploaded in a single contiguous array.  
  */
-static void upload_wm_samplers( struct brw_context *brw )
+static int upload_wm_samplers( struct brw_context *brw )
 {
    struct wm_sampler_key key;
+   struct brw_winsys_reloc reloc[BRW_MAX_TEX_UNIT];
+   enum pipe_error ret;
    int i;
 
+   brw_wm_sampler_update_default_colors(brw);
    brw_wm_sampler_populate_key(brw, &key);
 
    if (brw->wm.sampler_count != key.sampler_count) {
@@ -306,55 +177,48 @@ static void upload_wm_samplers( struct brw_context *brw )
       brw->state.dirty.cache |= CACHE_NEW_SAMPLER;
    }
 
-   brw->sws->bo_unreference(brw->wm.sampler_bo);
-   brw->wm.sampler_bo = NULL;
-   if (brw->wm.sampler_count == 0)
-      return;
+   if (brw->wm.sampler_count == 0) {
+      bo_reference(&brw->wm.sampler_bo, NULL);
+      return PIPE_OK;
+   }
+
+   /* Emit SDC relocations */
+   for (i = 0; i < key.sampler_count; i++) {
+      make_reloc( &reloc[i],
+                  BRW_USAGE_SAMPLER,
+                  0,
+                  i * sizeof(struct brw_sampler_state) +
+                  offsetof(struct brw_sampler_state, ss2),
+                  brw->wm.sdc_bo[i]);
+   }
+
 
-   brw->wm.sampler_bo = brw_search_cache(&brw->cache, BRW_SAMPLER,
-                                        &key, sizeof(key),
-                                        brw->wm.sdc_bo, key.sampler_count,
-                                        NULL);
+   if (brw_search_cache(&brw->cache, BRW_SAMPLER,
+                        &key, sizeof(key),
+                        reloc, key.sampler_count,
+                        NULL,
+                        &brw->wm.sampler_bo))
+      return PIPE_OK;
 
    /* 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];
+   ret = brw_upload_cache(&brw->cache, BRW_SAMPLER,
+                          &key, sizeof(key),
+                          reloc, key.sampler_count,
+                          &key.sampler, sizeof(key.sampler),
+                          NULL, NULL,
+                          &brw->wm.sampler_bo);
+   if (ret)
+      return ret;
 
-      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]);
-      }
-   }
+   return 0;
 }
 
 const struct brw_tracked_state brw_wm_samplers = {
    .dirty = {
-      .mesa = _NEW_TEXTURE,
+      .mesa = PIPE_NEW_BOUND_TEXTURES | PIPE_NEW_SAMPLERS,
       .brw = 0,
       .cache = 0
    },