llvmpipe: Update for TGSI_INTERPOLATE_COLOR.
[mesa.git] / src / gallium / drivers / llvmpipe / lp_state_fs.c
index ae207617cc173e07d83108a5f8686945a9d0ca69..c7bab82b0882bd126f285e8414aa05a9f8ea9a03 100644 (file)
@@ -334,7 +334,8 @@ generate_fs(struct gallivm_state *gallivm,
    
    /* Build the actual shader */
    lp_build_tgsi_soa(gallivm, tokens, type, &mask,
-                     consts_ptr, interp->pos, interp->inputs,
+                     consts_ptr, NULL, /* sys values array */
+                     interp->pos, interp->inputs,
                      outputs, sampler, &shader->info.base);
 
    /* Alpha test */
@@ -515,7 +516,6 @@ generate_fragment(struct llvmpipe_context *lp,
    struct lp_type fs_type;
    struct lp_type blend_type;
    LLVMTypeRef fs_elem_type;
-   LLVMTypeRef fs_int_vec_type;
    LLVMTypeRef blend_vec_type;
    LLVMTypeRef arg_types[11];
    LLVMTypeRef func_type;
@@ -545,6 +545,7 @@ generate_fragment(struct llvmpipe_context *lp,
    unsigned i;
    unsigned chan;
    unsigned cbuf;
+   boolean cbuf0_write_all;
 
    /* Adjust color input interpolation according to flatshade state:
     */
@@ -558,6 +559,15 @@ generate_fragment(struct llvmpipe_context *lp,
       }
    }
 
+   /* check if writes to cbuf[0] are to be copied to all cbufs */
+   cbuf0_write_all = FALSE;
+   for (i = 0;i < shader->info.base.num_properties; i++) {
+      if (shader->info.base.properties[i].name ==
+          TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS) {
+         cbuf0_write_all = TRUE;
+         break;
+      }
+   }
 
    /* TODO: actually pick these based on the fs and color buffer
     * characteristics. */
@@ -583,7 +593,6 @@ generate_fragment(struct llvmpipe_context *lp,
     */
 
    fs_elem_type = lp_build_elem_type(gallivm, fs_type);
-   fs_int_vec_type = lp_build_int_vec_type(gallivm, fs_type);
 
    blend_vec_type = lp_build_vec_type(gallivm, blend_type);
 
@@ -696,9 +705,10 @@ generate_fragment(struct llvmpipe_context *lp,
                   mask_input,
                   counter);
 
-      for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++)
-        for(chan = 0; chan < NUM_CHANNELS; ++chan)
-           fs_out_color[cbuf][chan][i] = out_color[cbuf][chan];
+      for (cbuf = 0; cbuf < key->nr_cbufs; cbuf++)
+         for (chan = 0; chan < NUM_CHANNELS; ++chan)
+            fs_out_color[cbuf][chan][i] =
+               out_color[cbuf * !cbuf0_write_all][chan];
    }
 
    sampler->destroy(sampler);
@@ -794,6 +804,7 @@ generate_fragment(struct llvmpipe_context *lp,
       LLVMWriteBitcodeToFile(gallivm->module, "llvmpipe.bc");
    }
 
+   variant->nr_instrs += lp_build_count_instructions(function);
    /*
     * Translate the LLVM IR into machine code.
     */
@@ -1014,19 +1025,15 @@ llvmpipe_create_fs_state(struct pipe_context *pipe,
       case TGSI_INTERPOLATE_PERSPECTIVE:
         shader->inputs[i].interp = LP_INTERP_PERSPECTIVE;
         break;
+      case TGSI_INTERPOLATE_COLOR:
+        shader->inputs[i].interp = LP_INTERP_COLOR;
+        break;
       default:
         assert(0);
         break;
       }
 
       switch (shader->info.base.input_semantic_name[i]) {
-      case TGSI_SEMANTIC_COLOR:
-         /* Colors may be either linearly or constant interpolated in
-         * the fragment shader, but that information isn't available
-         * here.  Mark color inputs and fix them up later.
-          */
-        shader->inputs[i].interp = LP_INTERP_COLOR;
-         break;
       case TGSI_SEMANTIC_FACE:
         shader->inputs[i].interp = LP_INTERP_FACING;
         break;
@@ -1119,6 +1126,7 @@ llvmpipe_remove_shader_variant(struct llvmpipe_context *lp,
    /* remove from context's list */
    remove_from_list(&variant->list_item_global);
    lp->nr_fs_variants--;
+   lp->nr_fs_instrs -= variant->nr_instrs;
 
    FREE(variant);
 }
@@ -1282,7 +1290,8 @@ make_variant_key(struct llvmpipe_context *lp,
        *
        * Also, force rgb/alpha func/factors match, to make AoS blending easier.
        */
-      if (format_desc->swizzle[3] > UTIL_FORMAT_SWIZZLE_W) {
+      if (format_desc->swizzle[3] > UTIL_FORMAT_SWIZZLE_W ||
+         format_desc->swizzle[3] == format_desc->swizzle[0]) {
          blend_rt->rgb_src_factor   = force_dst_alpha_one(blend_rt->rgb_src_factor);
          blend_rt->rgb_dst_factor   = force_dst_alpha_one(blend_rt->rgb_dst_factor);
          blend_rt->alpha_func       = blend_rt->rgb_func;
@@ -1340,11 +1349,22 @@ llvmpipe_update_fs(struct llvmpipe_context *lp)
       /* variant not found, create it now */
       int64_t t0, t1, dt;
       unsigned i;
+      unsigned variants_to_cull;
+
+      if (0) {
+         debug_printf("%u variants,\t%u instrs,\t%u instrs/variant\n",
+                      lp->nr_fs_variants,
+                      lp->nr_fs_instrs,
+                      lp->nr_fs_variants ? lp->nr_fs_instrs / lp->nr_fs_variants : 0);
+      }
 
       /* First, check if we've exceeded the max number of shader variants.
        * If so, free 25% of them (the least recently used ones).
        */
-      if (lp->nr_fs_variants >= LP_MAX_SHADER_VARIANTS) {
+      variants_to_cull = lp->nr_fs_variants >= LP_MAX_SHADER_VARIANTS ? LP_MAX_SHADER_VARIANTS / 4 : 0;
+
+      if (variants_to_cull ||
+          lp->nr_fs_instrs >= LP_MAX_SHADER_INSTRUCTIONS) {
          struct pipe_context *pipe = &lp->pipe;
 
          /*
@@ -1354,9 +1374,20 @@ llvmpipe_update_fs(struct llvmpipe_context *lp)
           */
          llvmpipe_finish(pipe, __FUNCTION__);
 
-         for (i = 0; i < LP_MAX_SHADER_VARIANTS / 4; i++) {
+         /*
+          * We need to re-check lp->nr_fs_variants because an arbitrarliy large
+          * number of shader variants (potentially all of them) could be
+          * pending for destruction on flush.
+          */
+
+         for (i = 0; i < variants_to_cull || lp->nr_fs_instrs >= LP_MAX_SHADER_INSTRUCTIONS; i++) {
             struct lp_fs_variant_list_item *item;
+            if (is_empty_list(&lp->fs_variants_list)) {
+               break;
+            }
             item = last_elem(&lp->fs_variants_list);
+            assert(item);
+            assert(item->base);
             llvmpipe_remove_shader_variant(lp, item->base);
          }
       }
@@ -1378,6 +1409,7 @@ llvmpipe_update_fs(struct llvmpipe_context *lp)
          insert_at_head(&shader->variants, &variant->list_item_local);
          insert_at_head(&lp->fs_variants_list, &variant->list_item_global);
          lp->nr_fs_variants++;
+         lp->nr_fs_instrs += variant->nr_instrs;
          shader->variants_cached++;
       }
    }