Performance improvements: Enable blending only when needed

Never draw the background image with blending.

Draw card images with blending only when requested. By
default, blending is enabled, but [MVC]CarouselView
subclasses can disable it.

Change-Id: Ia66f0fb7df45881481f0b782983402fcecb4a29a
diff --git a/carousel/java/com/android/ex/carousel/CarouselController.java b/carousel/java/com/android/ex/carousel/CarouselController.java
index ca0c5f8..9f3444e 100644
--- a/carousel/java/com/android/ex/carousel/CarouselController.java
+++ b/carousel/java/com/android/ex/carousel/CarouselController.java
@@ -64,6 +64,7 @@
     private int mPrefetchCardCount = DEFAULT_PREFETCH_CARD_COUNT;
     private boolean mDrawDetailBelowCard = false;
     private boolean mDetailTexturesCentered = false;
+    private boolean mDrawCardsWithBlending = true;
     private boolean mDrawRuler = true;
     private float mStartAngle;
     private float mRadius = DEFAULT_RADIUS;
@@ -227,6 +228,20 @@
     }
 
     /**
+     * Set whether blending is enabled while drawing the card textures. This should be true when
+     * translucent cards need to be supported, and false when all cards are fully opaque. Setting
+     * to false provides a performance boost.
+     *
+     * @param enabled True to enable blending, and false to disable it.
+     */
+    public void setDrawCardsWithBlending(boolean enabled) {
+        mDrawCardsWithBlending = enabled;
+        if (mRenderScript != null) {
+            mRenderScript.setDrawCardsWithBlending(enabled);
+        }
+    }
+
+    /**
      * Set whether to draw a ruler from the card to the detail texture
      *
      * @param drawRuler True to draw a ruler, false to draw nothing where the ruler would go.
diff --git a/carousel/java/com/android/ex/carousel/CarouselRS.java b/carousel/java/com/android/ex/carousel/CarouselRS.java
index 134057c..dbc543f 100644
--- a/carousel/java/com/android/ex/carousel/CarouselRS.java
+++ b/carousel/java/com/android/ex/carousel/CarouselRS.java
@@ -20,16 +20,9 @@
 import android.graphics.Bitmap;
 import android.renderscript.*;
 import android.renderscript.RenderScript.RSMessage;
-import android.renderscript.Sampler.Value;
-import android.renderscript.ProgramRaster.CullMode;
 import android.util.Log;
 
-import com.android.internal.R;
-
 import static android.renderscript.Element.*;
-import static android.renderscript.Sampler.Value.LINEAR;
-import static android.renderscript.Sampler.Value.WRAP;
-import static android.renderscript.Sampler.Value.CLAMP;
 
 /**
  * This is a support class for Carousel renderscript.  It handles most of the low-level interactions
@@ -65,6 +58,7 @@
     private ScriptField_Card mCards;
     private ScriptField_FragmentShaderConstants_s mFSConst;
     private ProgramStore mProgramStore;
+    private ProgramStore mProgramStoreOpaque;
     private ProgramFragment mSingleTextureFragmentProgram;
     private ProgramFragment mMultiTextureFragmentProgram;
     private ProgramVertex mVertexProgram;
@@ -336,6 +330,11 @@
         programStoreBuilder.setDepthMask(true);
         mProgramStore = programStoreBuilder.create();
         mScript.set_programStore(mProgramStore);
+
+        programStoreBuilder.setBlendFunc(ProgramStore.BlendSrcFunc.ONE,
+                ProgramStore.BlendDstFunc.ZERO);
+        mProgramStoreOpaque = programStoreBuilder.create();
+        mScript.set_programStoreOpaque(mProgramStoreOpaque);
     }
 
     public void createCards(int count)
@@ -381,6 +380,10 @@
         mScript.set_detailTexturesCentered(centered);
     }
 
+    public void setDrawCardsWithBlending(boolean enabled) {
+        mScript.set_drawCardsWithBlending(enabled);
+    }
+
     public void setDrawRuler(boolean drawRuler) {
         mScript.set_drawRuler(drawRuler);
     }
diff --git a/carousel/java/com/android/ex/carousel/CarouselView.java b/carousel/java/com/android/ex/carousel/CarouselView.java
index 7eaecec..f4bf569 100644
--- a/carousel/java/com/android/ex/carousel/CarouselView.java
+++ b/carousel/java/com/android/ex/carousel/CarouselView.java
@@ -73,6 +73,7 @@
     private int mPrefetchCardCount = DEFAULT_PREFETCH_CARD_COUNT;
     private boolean mDrawDetailBelowCard = false;
     private boolean mDetailTexturesCentered = false;
+    private boolean mDrawCardsWithBlending = true;
     private boolean mDrawRuler = true;
     private float mStartAngle;
     private float mRadius = DEFAULT_RADIUS;
@@ -287,6 +288,13 @@
         }
     }
 
+    public void setDrawCardsWithBlending(boolean enabled) {
+        mDrawCardsWithBlending = enabled;
+        if (mRenderScript != null) {
+            mRenderScript.setDrawCardsWithBlending(enabled);
+        }
+    }
+
     /**
      * Set whether to draw a ruler from the card to the detail texture
      *
diff --git a/carousel/java/com/android/ex/carousel/MVCCarouselView.java b/carousel/java/com/android/ex/carousel/MVCCarouselView.java
index 2f022c1..8368242 100644
--- a/carousel/java/com/android/ex/carousel/MVCCarouselView.java
+++ b/carousel/java/com/android/ex/carousel/MVCCarouselView.java
@@ -217,6 +217,17 @@
     }
 
     /**
+     * Set whether blending is enabled while drawing the card textures. This should be true when
+     * translucent cards need to be supported, and false when all cards are fully opaque. Setting
+     * to false provides a performance boost.
+     *
+     * @param enabled True to enable blending, and false to disable it.
+     */
+    public void setDrawCardsWithBlending(boolean enabled) {
+        mController.setDrawCardsWithBlending(enabled);
+    }
+
+    /**
      * Set whether to draw a ruler from the card to the detail texture
      *
      * @param drawRuler True to draw a ruler, false to draw nothing where the ruler would go.
diff --git a/carousel/java/com/android/ex/carousel/carousel.rs b/carousel/java/com/android/ex/carousel/carousel.rs
index 612ba92..7140edd 100644
--- a/carousel/java/com/android/ex/carousel/carousel.rs
+++ b/carousel/java/com/android/ex/carousel/carousel.rs
@@ -103,6 +103,7 @@
 bool drawDetailBelowCard; // whether detail goes above (false) or below (true) the card
 // TODO(jshuma): Replace detailTexturesCentered with a detailTextureAlignment mode enum
 bool detailTexturesCentered; // line up detail center and card center (instead of left edges)
+bool drawCardsWithBlending; // Enable blending while drawing cards (for translucent card textures)
 bool drawRuler; // whether to draw a ruler from the card to the detail texture
 float radius; // carousel radius. Cards will be centered on a circle with this radius
 float cardRotation; // rotation of card in XY plane relative to Z=1
@@ -114,6 +115,7 @@
 float rezInCardCount; // this controls how rapidly distant card textures will be rez-ed in
 float detailFadeRate; // rate at which details fade as they move into the distance
 rs_program_store programStore;
+rs_program_store programStoreOpaque;
 rs_program_fragment singleTextureFragmentProgram;
 rs_program_fragment multiTextureFragmentProgram;
 rs_program_vertex vertexProgram;
@@ -1226,7 +1228,6 @@
     int64_t currentTime = rsUptimeMillis();
 
     rsgBindProgramVertex(vertexProgram);
-    rsgBindProgramStore(programStore);
     rsgBindProgramRaster(rasterProgram);
     rsgBindSampler(singleTextureFragmentProgram, 0, linearClamp);
     rsgBindSampler(multiTextureFragmentProgram, 0, linearClamp);
@@ -1246,6 +1247,7 @@
     }
 
     rsgBindProgramFragment(singleTextureFragmentProgram);
+    rsgBindProgramStore(programStoreOpaque);
     drawBackground();
 
     updateCameraMatrix(rsgGetWidth(), rsgGetHeight());
@@ -1257,8 +1259,17 @@
 
     updateCardResources(currentTime);
 
-    stillAnimating |= drawCards(currentTime);
-    stillAnimating |= drawDetails(currentTime);
+    // Draw cards opaque only if requested, and always draw detail textures with blending.
+    if (drawCardsWithBlending) {
+        rsgBindProgramStore(programStore);
+        stillAnimating |= drawCards(currentTime);
+        stillAnimating |= drawDetails(currentTime);
+    } else {
+        // programStoreOpaque is already bound
+        stillAnimating |= drawCards(currentTime);
+        rsgBindProgramStore(programStore);
+        stillAnimating |= drawDetails(currentTime);
+    }
 
     if (debugPicking) {
         renderWithRays();