Home | History | Annotate | Download | only in com.example.android.basicrenderscript
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.basicrenderscript;
     18 
     19 import android.app.Activity;
     20 import android.graphics.Bitmap;
     21 import android.graphics.BitmapFactory;
     22 import android.os.AsyncTask;
     23 import android.os.Bundle;
     24 import android.widget.ImageView;
     25 import android.widget.SeekBar;
     26 import android.widget.SeekBar.OnSeekBarChangeListener;
     27 import android.support.v8.renderscript.*;
     28 
     29 public class MainActivity extends Activity {
     30     /* Number of bitmaps that is used for renderScript thread and UI thread synchronization.
     31        Ideally, this can be reduced to 2, however in some devices, 2 buffers still showing tierings on UI.
     32        Investigating a root cause.
     33      */
     34     private final int NUM_BITMAPS = 3;
     35     private int mCurrentBitmap = 0;
     36     private Bitmap mBitmapIn;
     37     private Bitmap[] mBitmapsOut;
     38     private ImageView mImageView;
     39 
     40     private RenderScript mRS;
     41     private Allocation mInAllocation;
     42     private Allocation[] mOutAllocations;
     43     private ScriptC_saturation mScript;
     44 
     45     @Override
     46     protected void onCreate(Bundle savedInstanceState) {
     47         super.onCreate(savedInstanceState);
     48 
     49         setContentView(R.layout.main_layout);
     50 
     51         /*
     52          * Initialize UI
     53          */
     54         mBitmapIn = loadBitmap(R.drawable.data);
     55         mBitmapsOut = new Bitmap[NUM_BITMAPS];
     56         for (int i = 0; i < NUM_BITMAPS; ++i) {
     57             mBitmapsOut[i] = Bitmap.createBitmap(mBitmapIn.getWidth(),
     58                     mBitmapIn.getHeight(), mBitmapIn.getConfig());
     59         }
     60 
     61         mImageView = (ImageView) findViewById(R.id.imageView);
     62         mImageView.setImageBitmap(mBitmapsOut[mCurrentBitmap]);
     63         mCurrentBitmap += (mCurrentBitmap + 1) % NUM_BITMAPS;
     64 
     65         SeekBar seekbar = (SeekBar) findViewById(R.id.seekBar1);
     66         seekbar.setProgress(50);
     67         seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
     68             public void onProgressChanged(SeekBar seekBar, int progress,
     69                                           boolean fromUser) {
     70                 float max = 2.0f;
     71                 float min = 0.0f;
     72                 float f = (float) ((max - min) * (progress / 100.0) + min);
     73                 updateImage(f);
     74             }
     75 
     76             @Override
     77             public void onStartTrackingTouch(SeekBar seekBar) {
     78             }
     79 
     80             @Override
     81             public void onStopTrackingTouch(SeekBar seekBar) {
     82             }
     83         });
     84 
     85         /*
     86          * Create renderScript
     87          */
     88         createScript();
     89 
     90         /*
     91          * Invoke renderScript kernel and update imageView
     92          */
     93         updateImage(1.0f);
     94     }
     95 
     96     /*
     97      * Initialize RenderScript
     98      * In the sample, it creates RenderScript kernel that performs saturation manipulation.
     99      */
    100     private void createScript() {
    101         //Initialize RS
    102         mRS = RenderScript.create(this);
    103 
    104         //Allocate buffers
    105         mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn);
    106         mOutAllocations = new Allocation[NUM_BITMAPS];
    107         for (int i = 0; i < NUM_BITMAPS; ++i) {
    108             mOutAllocations[i] = Allocation.createFromBitmap(mRS, mBitmapsOut[i]);
    109         }
    110 
    111         //Load script
    112         mScript = new ScriptC_saturation(mRS);
    113     }
    114 
    115     /*
    116      * In the AsyncTask, it invokes RenderScript intrinsics to do a filtering.
    117      * After the filtering is done, an operation blocks at Allication.copyTo() in AsyncTask thread.
    118      * Once all operation is finished at onPostExecute() in UI thread, it can invalidate and update ImageView UI.
    119      */
    120     private class RenderScriptTask extends AsyncTask<Float, Integer, Integer> {
    121         Boolean issued = false;
    122 
    123         protected Integer doInBackground(Float... values) {
    124             int index = -1;
    125             if (isCancelled() == false) {
    126                 issued = true;
    127                 index = mCurrentBitmap;
    128 
    129                 /*
    130                  * Set global variable in RS
    131                  */
    132                 mScript.set_saturationValue(values[0]);
    133 
    134                 /*
    135                  * Invoke saturation filter kernel
    136                  */
    137                 mScript.forEach_saturation(mInAllocation, mOutAllocations[index]);
    138 
    139                 /*
    140                  * Copy to bitmap and invalidate image view
    141                  */
    142                 mOutAllocations[index].copyTo(mBitmapsOut[index]);
    143                 mCurrentBitmap = (mCurrentBitmap + 1) % NUM_BITMAPS;
    144             }
    145             return index;
    146         }
    147 
    148         void updateView(Integer result) {
    149             if (result != -1) {
    150                 // Request UI update
    151                 mImageView.setImageBitmap(mBitmapsOut[result]);
    152                 mImageView.invalidate();
    153             }
    154         }
    155 
    156         protected void onPostExecute(Integer result) {
    157             updateView(result);
    158         }
    159 
    160         protected void onCancelled(Integer result) {
    161             if (issued) {
    162                 updateView(result);
    163             }
    164         }
    165     }
    166 
    167     RenderScriptTask currentTask = null;
    168 
    169     /*
    170     Invoke AsynchTask and cancel previous task.
    171     When AsyncTasks are piled up (typically in slow device with heavy kernel),
    172     Only the latest (and already started) task invokes RenderScript operation.
    173      */
    174     private void updateImage(final float f) {
    175         if (currentTask != null)
    176             currentTask.cancel(false);
    177         currentTask = new RenderScriptTask();
    178         currentTask.execute(f);
    179     }
    180 
    181     /*
    182     Helper to load Bitmap from resource
    183      */
    184     private Bitmap loadBitmap(int resource) {
    185         final BitmapFactory.Options options = new BitmapFactory.Options();
    186         options.inPreferredConfig = Bitmap.Config.ARGB_8888;
    187         return BitmapFactory.decodeResource(getResources(), resource, options);
    188     }
    189 
    190 }
    191