Merge branch 'gallium-0.1' into gallium-0.2
[mesa.git] / src / mesa / main / texenvprogram.c
index 512d52704d822c5659598d5ac7bd3248e9c1e15e..713ff3d256424a64b17987e90fa6969e5b5ca5e6 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
 #include "enums.h"
 #include "shader/program.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 "shader/programopt.h"
 #include "texenvprogram.h"
 
 
@@ -411,9 +413,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.
@@ -593,7 +595,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)
@@ -915,14 +917,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 );
@@ -951,9 +953,17 @@ static void load_texture( struct texenv_fragment_program *p, GLuint unit )
         p->src_texture[unit] = emit_texld( p, OPCODE_TXP,
                                            tmp, WRITEMASK_XYZW, 
                                            unit, dim, texcoord );
+
         if (p->state->unit[unit].shadow)
            p->program->Base.ShadowSamplers |= 1 << unit;
-      } else
+
+         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);
    }
 }
@@ -1051,7 +1061,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
@@ -1069,7 +1079,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 */
         }
    }
 
@@ -1099,6 +1109,7 @@ create_new_program(GLcontext *ctx, struct state_key *key,
        * a reduced value and not what is expected in FogOption
        */
       p.program->FogOption = ctx->Fog.Mode;
+      p.program->Base.InputsRead |= FRAG_BIT_FOGC; /* XXX new */
    } else
       p.program->FogOption = GL_NONE;
 
@@ -1114,15 +1125,21 @@ create_new_program(GLcontext *ctx, struct state_key *key,
    ASSERT(p.program->Base.NumInstructions <= MAX_INSTRUCTIONS);
 
    /* Allocate final instruction array */
-   program->Base.Instructions
-      = _mesa_alloc_instructions(program->Base.NumInstructions);
-   if (!program->Base.Instructions) {
+   p.program->Base.Instructions
+      = _mesa_alloc_instructions(p.program->Base.NumInstructions);
+   if (!p.program->Base.Instructions) {
       _mesa_error(ctx, GL_OUT_OF_MEMORY,
                   "generating tex env program");
       return;
    }
-   _mesa_copy_instructions(program->Base.Instructions, instBuffer,
-                           program->Base.NumInstructions);
+   _mesa_copy_instructions(p.program->Base.Instructions, instBuffer,
+                           p.program->Base.NumInstructions);
+
+   if (p.program->FogOption) {
+      _mesa_append_fog_code(ctx, p.program);
+      p.program->FogOption = GL_NONE;
+   }
+
 
    /* Notify driver the fragment program has (actually) changed.
     */
@@ -1138,106 +1155,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 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(GLcontext *ctx, 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);
-         _mesa_reference_fragprog(ctx, &c->data, NULL);
-        _mesa_free(c);
-      }
-      cache->items[i] = NULL;
-   }
-
-
-   cache->n_items = 0;
-}
-
-
-static void cache_item( GLcontext *ctx,
-                        struct texenvprog_cache *cache,
-                       GLuint hash,
-                       const struct state_key *key,
-                        struct gl_fragment_program *prog)
+/**
+ * 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 = CALLOC_STRUCT(texenvprog_cache_item);
-   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 = prog;
+      create_new_program(ctx, &key, prog);
 
-   if (cache->n_items > cache->size * 1.5) {
-      if (cache->size < 1000)
-        rehash(cache);
-      else 
-        clear_cache(ctx, 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;
-}
 
 
 /**
@@ -1248,44 +1194,22 @@ 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);
 
    /* If a conventional fragment program/shader isn't in effect... */
    if (!ctx->FragmentProgram._Enabled &&
-       (!ctx->Shader.CurrentProgram || !ctx->Shader.CurrentProgram->FragmentProgram)) {
+       (!ctx->Shader.CurrentProgram ||
+        !ctx->Shader.CurrentProgram->FragmentProgram) ) 
+   {
       struct gl_fragment_program *newProg;
 
-      make_state_key(ctx, &key);
-      hash = hash_key(&key);
-      
-      newProg = search_cache(&ctx->Texture.env_fp_cache, hash, &key, sizeof(key));
-
-      if (!newProg) {
-         /* create new tex env program */
-
-         if (0)
-            _mesa_printf("Building new texenv proggy for key %x\n", hash);
-
-         newProg = (struct gl_fragment_program *) 
-            ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
-
-         create_new_program(ctx, &key, newProg);
-
-         /* Our ownership of newProg is transferred to the cache */
-         cache_item(ctx, &ctx->Texture.env_fp_cache, hash, &key, newProg);
-      }
+      newProg = _mesa_get_fixed_func_fragment_program(ctx);
 
       _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, newProg);
       _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram, newProg);
    } 
-   else {
-      /* _Current pointer has been updated in update_program */
-      /* ctx->FragmentProgram._Current = ctx->FragmentProgram.Current; */
-   }
 
    /* Tell the driver about the change.  Could define a new target for
     * this?
@@ -1295,21 +1219,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, &ctx->Texture.env_fp_cache);
-   _mesa_free(ctx->Texture.env_fp_cache.items);
-}