Code drop from //branches/cupcake/...@124589
diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp
index 90c275e..1cd189c 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.cpp
+++ b/libpixelflinger/codeflinger/GGLAssembler.cpp
@@ -151,6 +151,7 @@
         // Destination is zero (beware of logic ops)
     }
     
+    int fbComponents = 0;
     const int masking = GGL_READ_NEEDS(MASK_ARGB, needs.n);
     for (int i=0 ; i<4 ; i++) {
         const int mask = 1<<i;
@@ -176,9 +177,14 @@
 
         mBlending |= (info.blend ? mask : 0);
         mMasking |= (mCbFormat.c[i].h && info.masked) ? mask : 0;
+        fbComponents |= mCbFormat.c[i].h ? mask : 0;
     }
 
-
+    mAllMasked = (mMasking == fbComponents);
+    if (mAllMasked) {
+        mDithering = 0;
+    }
+    
     fragment_parts_t parts;
 
     // ------------------------------------------------------------------------
@@ -226,8 +232,10 @@
             build_textures(parts, regs);
         }        
 
-        if ((blending & (FACTOR_DST|BLEND_DST)) || mMasking ||
-                (mLogicOp & LOGIC_OP_DST)) {
+        if ((blending & (FACTOR_DST|BLEND_DST)) || 
+                (mMasking && !mAllMasked) ||
+                (mLogicOp & LOGIC_OP_DST)) 
+        {
             // blending / logic_op / masking need the framebuffer
             mDstPixel.setTo(regs.obtain(), &mCbFormat);
 
@@ -284,14 +292,16 @@
             pixel = mDstPixel;
         }
         
-        // logic operation
-        build_logic_op(pixel, regs);
-
-        // masking
-        build_masking(pixel, regs); 
-
-        comment("store");
-        store(parts.cbPtr, pixel, WRITE_BACK);
+        if (!mAllMasked) {
+            // logic operation
+            build_logic_op(pixel, regs);
+    
+            // masking
+            build_masking(pixel, regs); 
+    
+            comment("store");
+            store(parts.cbPtr, pixel, WRITE_BACK);
+        }
     }
 
     if (registerFile().status())
@@ -322,7 +332,9 @@
         build_smooth_shade(parts);
         build_iterate_z(parts);
         build_iterate_f(parts);
-        ADD(AL, 0, parts.cbPtr.reg, parts.cbPtr.reg, imm(parts.cbPtr.size>>3));
+        if (!mAllMasked) {
+            ADD(AL, 0, parts.cbPtr.reg, parts.cbPtr.reg, imm(parts.cbPtr.size>>3));
+        }
         SUB(AL, S, parts.count.reg, parts.count.reg, imm(1<<16));
         B(PL, "fragment_loop");
         epilog(registerFile().touched());
@@ -370,16 +382,18 @@
         MOV(AL, 0, parts.count.reg, reg_imm(parts.count.reg, LSL, 16));
     }
 
-    // compute dst ptr
-    comment("compute color-buffer pointer");
-    const int cb_bits = mCbFormat.size*8;
-    int Rs = scratches.obtain();
-    parts.cbPtr.setTo(obtainReg(), cb_bits);
-    CONTEXT_LOAD(Rs, state.buffers.color.stride);
-    CONTEXT_LOAD(parts.cbPtr.reg, state.buffers.color.data);
-    SMLABB(AL, Rs, Ry, Rs, Rx);  // Rs = Rx + Ry*Rs
-    base_offset(parts.cbPtr, parts.cbPtr, Rs);
-    scratches.recycle(Rs);
+    if (!mAllMasked) {
+        // compute dst ptr
+        comment("compute color-buffer pointer");
+        const int cb_bits = mCbFormat.size*8;
+        int Rs = scratches.obtain();
+        parts.cbPtr.setTo(obtainReg(), cb_bits);
+        CONTEXT_LOAD(Rs, state.buffers.color.stride);
+        CONTEXT_LOAD(parts.cbPtr.reg, state.buffers.color.data);
+        SMLABB(AL, Rs, Ry, Rs, Rx);  // Rs = Rx + Ry*Rs
+        base_offset(parts.cbPtr, parts.cbPtr, Rs);
+        scratches.recycle(Rs);
+    }
     
     // init fog
     const int need_fog = GGL_READ_NEEDS(P_FOG, needs.p);
@@ -904,8 +918,9 @@
 
 void GGLAssembler::build_masking(pixel_t& pixel, Scratch& regs)
 {
-    if (!mMasking)
+    if (!mMasking || mAllMasked) {
         return;
+    }
 
     comment("color mask");
 
@@ -928,7 +943,7 @@
 
     // There is no need to clear the masked components of the source
     // (unless we applied a logic op), because they're already zeroed 
-    // by contruction (masked components are not computed)
+    // by construction (masked components are not computed)
 
     if (mLogicOp) {
         const needs_t& needs = mBuilderContext.needs;
diff --git a/libpixelflinger/codeflinger/GGLAssembler.h b/libpixelflinger/codeflinger/GGLAssembler.h
index ccaf43d..d1d29f0 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.h
+++ b/libpixelflinger/codeflinger/GGLAssembler.h
@@ -363,6 +363,10 @@
                     const component_t& incoming,
                     const pixel_t& texel, int component, int tmu);
 
+    void    add(  component_t& dest,
+                    const component_t& incoming,
+                    const pixel_t& texel, int component);
+
     // load/store stuff
     void    store(const pointer_t& addr, const pixel_t& src, uint32_t flags=0);
     void    load(const pointer_t& addr, const pixel_t& dest, uint32_t flags=0);
@@ -517,6 +521,7 @@
     component_info_t    mInfo[4];
     int                 mBlending;
     int                 mMasking;
+    int                 mAllMasked;
     int                 mLogicOp;
     int                 mAlphaTest;
     int                 mAA;
diff --git a/libpixelflinger/codeflinger/blending.cpp b/libpixelflinger/codeflinger/blending.cpp
index 6d3b282..f10217b 100644
--- a/libpixelflinger/codeflinger/blending.cpp
+++ b/libpixelflinger/codeflinger/blending.cpp
@@ -50,6 +50,12 @@
         integer_t factor(scratches.obtain(), 16, CORRUPTIBLE);
         CONTEXT_LOAD(factor.reg, generated_vars.f);
 
+        // clamp fog factor (TODO: see if there is a way to guarantee
+        // we won't overflow, when setting the iterators)
+        BIC(AL, 0, factor.reg, factor.reg, reg_imm(factor.reg, ASR, 31));
+        CMP(AL, factor.reg, imm( 0x10000 ));
+        MOV(HS, 0, factor.reg, imm( 0x10000 ));
+
         build_blendFOneMinusF(temp, factor, fragment, fogColor);
     }
 }
diff --git a/libpixelflinger/codeflinger/load_store.cpp b/libpixelflinger/codeflinger/load_store.cpp
index 514ce07..93c5825 100644
--- a/libpixelflinger/codeflinger/load_store.cpp
+++ b/libpixelflinger/codeflinger/load_store.cpp
@@ -168,7 +168,7 @@
 void GGLAssembler::expand(component_t& d, const component_t& s, int dbits)
 {
     integer_t r(d.reg, 32, d.flags);
-    expand(r, d, dbits);
+    expand(r, s, dbits);
     d = component_t(r);
 }
 
diff --git a/libpixelflinger/codeflinger/texturing.cpp b/libpixelflinger/codeflinger/texturing.cpp
index 269b6c0..90e6584 100644
--- a/libpixelflinger/codeflinger/texturing.cpp
+++ b/libpixelflinger/codeflinger/texturing.cpp
@@ -1000,6 +1000,9 @@
                 case GGL_BLEND:
                     blend(fragment, incoming, texel, component, i);
                     break;
+                case GGL_ADD:
+                    add(fragment, incoming, texel, component);
+                    break;
                 }
             }
         }
@@ -1202,6 +1205,46 @@
     build_blendOneMinusFF(dest, factor, incomingNorm, color);
 }
 
+void GGLAssembler::add(
+        component_t& dest, 
+        const component_t& incoming,
+        const pixel_t& incomingTexel, int component)
+{
+    // RGBA:
+    // Cv = Cf + Ct;
+    Scratch locals(registerFile());
+    
+    component_t incomingTemp(incoming);
+
+    // use "dest" as a temporary for extracting the texel, unless "dest"
+    // overlaps "incoming".
+    integer_t texel(dest.reg, 32, CORRUPTIBLE);
+    if (dest.reg == incomingTemp.reg)
+        texel.reg = locals.obtain();
+    extract(texel, incomingTexel, component);
+
+    if (texel.s < incomingTemp.size()) {
+        expand(texel, texel, incomingTemp.size());
+    } else if (texel.s > incomingTemp.size()) {
+        if (incomingTemp.flags & CORRUPTIBLE) {
+            expand(incomingTemp, incomingTemp, texel.s);
+        } else {
+            incomingTemp.reg = locals.obtain();
+            expand(incomingTemp, incoming, texel.s);
+        }
+    }
+
+    if (incomingTemp.l) {
+        ADD(AL, 0, dest.reg, texel.reg,
+                reg_imm(incomingTemp.reg, LSR, incomingTemp.l));
+    } else {
+        ADD(AL, 0, dest.reg, texel.reg, incomingTemp.reg);
+    }
+    dest.l = 0;
+    dest.h = texel.size();
+    component_sat(dest);
+}
+
 // ----------------------------------------------------------------------------
 
 }; // namespace android