mesa: refactor: move glTexParameter-related functions into new texparam.c file
[mesa.git] / src / mesa / main / texenvprogram.c
index a554c033c4075dcf2528c769e3e33f275479885e..6877ef96f21797e1fbeccf5641b65bf7e0e5784f 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
  * 
- * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
  * All Rights Reserved.
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -29,6 +29,7 @@
 #include "macros.h"
 #include "enums.h"
 #include "shader/prog_parameter.h"
+#include "shader/prog_cache.h"
 #include "shader/prog_instruction.h"
 #include "shader/prog_print.h"
 #include "shader/prog_statevars.h"
 #include "texenvprogram.h"
 
 /**
- * According to Glean's texCombine test, no more than 21 instructions
- * are needed.  Allow a few extra just in case.
+ * This MAX is probably a bit generous, but that's OK.  There can be
+ * up to four instructions per texture unit (TEX + 3 for combine),
+ * then there's fog and specular add.
  */
-#define MAX_INSTRUCTIONS 24
+#define MAX_INSTRUCTIONS ((MAX_TEXTURE_UNITS * 4) + 12)
 
 #define DISASSEM (MESA_VERBOSE & VERBOSE_DISASSEM)
 
@@ -398,9 +400,9 @@ static struct ureg get_tex_temp( struct texenv_fragment_program *p )
 }
 
 
-static void release_temps( struct texenv_fragment_program *p )
+static void release_temps(GLcontext *ctx, struct texenv_fragment_program *p )
 {
-   GLuint max_temp = p->ctx->Const.FragmentProgram.MaxTemps;
+   GLuint max_temp = ctx->Const.FragmentProgram.MaxTemps;
 
    /* KW: To support tex_env_crossbar, don't release the registers in
     * temps_output.
@@ -461,8 +463,8 @@ static void emit_dst( struct prog_dst_register *dst,
    dst->File = ureg.file;
    dst->Index = ureg.idx;
    dst->WriteMask = mask;
-   dst->CondMask = 0;
-   dst->CondSwizzle = 0;
+   dst->CondMask = COND_TR;  /* always pass cond test */
+   dst->CondSwizzle = SWIZZLE_NOOP;
 }
 
 static struct prog_instruction *
@@ -478,6 +480,8 @@ emit_op(struct texenv_fragment_program *p,
    GLuint nr = p->program->Base.NumInstructions++;
    struct prog_instruction *inst = &p->program->Base.Instructions[nr];
       
+   assert(nr < MAX_INSTRUCTIONS);
+
    _mesa_init_instructions(inst, 1);
    inst->Opcode = op;
    
@@ -578,7 +582,7 @@ static struct ureg register_const4f( struct texenv_fragment_program *p,
    idx = _mesa_add_unnamed_constant( p->program->Base.Parameters, values, 4,
                                      &swizzle );
    ASSERT(swizzle == SWIZZLE_NOOP);
-   return make_ureg(PROGRAM_STATE_VAR, idx);
+   return make_ureg(PROGRAM_CONSTANT, idx);
 }
 
 #define register_scalar_const(p, s0)    register_const4f(p, s0, s0, s0, s0)
@@ -900,14 +904,14 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit)
     */
    if (alpha_shift || rgb_shift) {
       if (rgb_shift == alpha_shift) {
-        shift = register_scalar_const(p, 1<<rgb_shift);
+        shift = register_scalar_const(p, (GLfloat)(1<<rgb_shift));
       }
       else {
         shift = register_const4f(p, 
-                                 1<<rgb_shift,
-                                 1<<rgb_shift,
-                                 1<<rgb_shift,
-                                 1<<alpha_shift);
+                                 (GLfloat)(1<<rgb_shift),
+                                 (GLfloat)(1<<rgb_shift),
+                                 (GLfloat)(1<<rgb_shift),
+                                 (GLfloat)(1<<alpha_shift));
       }
       return emit_arith( p, OPCODE_MUL, dest, WRITEMASK_XYZW, 
                         saturate, out, shift, undef );
@@ -932,10 +936,16 @@ static void load_texture( struct texenv_fragment_program *p, GLuint unit )
                          
       /* TODO: Use D0_MASK_XY where possible.
        */
-      if (p->state->unit[unit].enabled) 
+      if (p->state->unit[unit].enabled) {
         p->src_texture[unit] = emit_texld( p, OPCODE_TXP,
                                            tmp, WRITEMASK_XYZW, 
                                            unit, dim, texcoord );
+         p->program->Base.SamplersUsed |= (1 << unit);
+         /* This identity mapping should already be in place
+          * (see _mesa_init_program_struct()) but let's be safe.
+          */
+         p->program->Base.SamplerUnits[unit] = unit;
+      }
       else
         p->src_texture[unit] = get_zero(p);
    }
@@ -1034,7 +1044,7 @@ create_new_program(GLcontext *ctx, struct state_key *key,
    p.one = undef;
 
    p.last_tex_stage = 0;
-   release_temps(&p);
+   release_temps(ctx, &p);
 
    if (key->enabled_units) {
       /* First pass - to support texture_env_crossbar, first identify
@@ -1052,7 +1062,7 @@ create_new_program(GLcontext *ctx, struct state_key *key,
       for (unit = 0 ; unit < ctx->Const.MaxTextureUnits; unit++)
         if (key->enabled_units & (1<<unit)) {
            p.src_previous = emit_texenv( &p, unit );
-           release_temps(&p);  /* release all temps */
+           release_temps(ctx, &p);     /* release all temps */
         }
    }
 
@@ -1128,107 +1138,35 @@ create_new_program(GLcontext *ctx, struct state_key *key,
 }
 
 
-static struct gl_fragment_program *
-search_cache(const struct texenvprog_cache *cache,
-             GLuint hash,
-             const void *key,
-             GLuint keysize)
-{
-   struct texenvprog_cache_item *c;
-
-   for (c = cache->items[hash % cache->size]; c; c = c->next) {
-      if (c->hash == hash && memcmp(c->key, key, keysize) == 0)
-        return (struct gl_fragment_program *) c->data;
-   }
-
-   return NULL;
-}
-
-static void rehash( struct texenvprog_cache *cache )
-{
-   struct texenvprog_cache_item **items;
-   struct texenvprog_cache_item *c, *next;
-   GLuint size, i;
-
-   size = cache->size * 3;
-   items = (struct texenvprog_cache_item**) _mesa_malloc(size * sizeof(*items));
-   _mesa_memset(items, 0, size * sizeof(*items));
-
-   for (i = 0; i < cache->size; i++)
-      for (c = cache->items[i]; c; c = next) {
-        next = c->next;
-        c->next = items[c->hash % size];
-        items[c->hash % size] = c;
-      }
-
-   _mesa_free(cache->items);
-   cache->items = items;
-   cache->size = size;
-}
-
-static void clear_cache( struct texenvprog_cache *cache )
-{
-   struct texenvprog_cache_item *c, *next;
-   GLuint i;
-
-   for (i = 0; i < cache->size; i++) {
-      for (c = cache->items[i]; c; c = next) {
-        next = c->next;
-        _mesa_free(c->key);
-        cache->ctx->Driver.DeleteProgram(cache->ctx,
-                                          (struct gl_program *) c->data);
-        _mesa_free(c);
-      }
-      cache->items[i] = NULL;
-   }
-
-
-   cache->n_items = 0;
-}
-
-
-static void cache_item( struct texenvprog_cache *cache,
-                       GLuint hash,
-                       const struct state_key *key,
-                       void *data )
+/**
+ * Return a fragment program which implements the current
+ * fixed-function texture, fog and color-sum operations.
+ */
+struct gl_fragment_program *
+_mesa_get_fixed_func_fragment_program(GLcontext *ctx)
 {
-   struct texenvprog_cache_item *c
-      = (struct texenvprog_cache_item *) MALLOC(sizeof(*c));
-   c->hash = hash;
+   struct gl_fragment_program *prog;
+   struct state_key key;
+       
+   make_state_key(ctx, &key);
+      
+   prog = (struct gl_fragment_program *)
+      _mesa_search_program_cache(ctx->FragmentProgram.Cache,
+                                 &key, sizeof(key));
 
-   c->key = _mesa_malloc(sizeof(*key));
-   memcpy(c->key, key, sizeof(*key));
+   if (!prog) {
+      prog = (struct gl_fragment_program *) 
+         ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
 
-   c->data = (struct gl_fragment_program *) data;
+      create_new_program(ctx, &key, prog);
 
-   if (cache->n_items > cache->size * 1.5) {
-      if (cache->size < 1000)
-        rehash(cache);
-      else 
-        clear_cache(cache);
+      _mesa_program_cache_insert(ctx, ctx->FragmentProgram.Cache,
+                                 &key, sizeof(key), &prog->Base);
    }
 
-   cache->n_items++;
-   c->next = cache->items[hash % cache->size];
-   cache->items[hash % cache->size] = c;
+   return prog;
 }
 
-static GLuint hash_key( const struct state_key *key )
-{
-   GLuint *ikey = (GLuint *)key;
-   GLuint hash = 0, i;
-
-   /* Make a slightly better attempt at a hash function:
-    */
-   for (i = 0; i < sizeof(*key)/sizeof(*ikey); i++)
-   {
-      hash += ikey[i];
-      hash += (hash << 10);
-      hash ^= (hash >> 6);
-   }
-
-   return hash;
-}
 
 
 /**
@@ -1239,8 +1177,6 @@ static GLuint hash_key( const struct state_key *key )
 void
 _mesa_UpdateTexEnvProgram( GLcontext *ctx )
 {
-   struct state_key key;
-   GLuint hash;
    const struct gl_fragment_program *prev = ctx->FragmentProgram._Current;
        
    ASSERT(ctx->FragmentProgram._MaintainTexEnvProgram);
@@ -1249,36 +1185,11 @@ _mesa_UpdateTexEnvProgram( GLcontext *ctx )
    if (!ctx->FragmentProgram._Enabled &&
        (!ctx->Shader.CurrentProgram ||
         !ctx->Shader.CurrentProgram->FragmentProgram) ) {
-      make_state_key(ctx, &key);
-      hash = hash_key(&key);
-      
-      ctx->FragmentProgram._Current =
-      ctx->FragmentProgram._TexEnvProgram =
-         search_cache(&ctx->Texture.env_fp_cache, hash, &key, sizeof(key));
-
-      if (!ctx->FragmentProgram._TexEnvProgram) {
-         if (0)
-            _mesa_printf("Building new texenv proggy for key %x\n", hash);
-
-         /* create new tex env program */
-        ctx->FragmentProgram._Current =
-         ctx->FragmentProgram._TexEnvProgram =
-            (struct gl_fragment_program *) 
-            ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
-
-         create_new_program(ctx, &key, ctx->FragmentProgram._TexEnvProgram);
 
-         cache_item(&ctx->Texture.env_fp_cache, hash, &key,
-                    ctx->FragmentProgram._TexEnvProgram);
-      }
-      else {
-         if (0)
-            _mesa_printf("Found existing texenv program for key %x\n", hash);
-      }
+      ctx->FragmentProgram._Current
+         = ctx->FragmentProgram._TexEnvProgram
+         = _mesa_get_fixed_func_fragment_program(ctx);
    } 
-   else {
-      ctx->FragmentProgram._Current = ctx->FragmentProgram.Current;
-   }
 
    /* Tell the driver about the change.  Could define a new target for
     * this?
@@ -1288,21 +1199,3 @@ _mesa_UpdateTexEnvProgram( GLcontext *ctx )
                          (struct gl_program *) ctx->FragmentProgram._Current);
    }
 }
-
-
-void _mesa_TexEnvProgramCacheInit( GLcontext *ctx )
-{
-   ctx->Texture.env_fp_cache.ctx = ctx;
-   ctx->Texture.env_fp_cache.size = 17;
-   ctx->Texture.env_fp_cache.n_items = 0;
-   ctx->Texture.env_fp_cache.items = (struct texenvprog_cache_item **)
-      _mesa_calloc(ctx->Texture.env_fp_cache.size * 
-                  sizeof(struct texenvprog_cache_item));
-}
-
-
-void _mesa_TexEnvProgramCacheDestroy( GLcontext *ctx )
-{
-   clear_cache(&ctx->Texture.env_fp_cache);
-   _mesa_free(ctx->Texture.env_fp_cache.items);
-}