Home | History | Annotate | Download | only in 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.graphics.Bitmap;
     20 import android.graphics.BitmapFactory;
     21 import android.os.AsyncTask;
     22 import android.os.Bundle;
     23 import android.support.v7.app.AppCompatActivity;
     24 import android.support.v8.renderscript.Allocation;
     25 import android.support.v8.renderscript.RenderScript;
     26 import android.widget.ImageView;
     27 import android.widget.SeekBar;
     28 import android.widget.SeekBar.OnSeekBarChangeListener;
     29 
     30 public class MainActivity extends AppCompatActivity {
     31 
     32     /**
     33      * Number of bitmaps that is used for RenderScript thread and UI thread synchronization.
     34      */
     35     private final int NUM_BITMAPS = 2;
     36     private int mCurrentBitmap = 0;
     37     private Bitmap mBitmapIn;
     38     private Bitmap[] mBitmapsOut;
     39     private ImageView mImageView;
     40 
     41     private Allocation mInAllocation;
     42     private Allocation[] mOutAllocations;
     43     private ScriptC_saturation mScript;
     44     private RenderScriptTask mCurrentTask;
     45 
     46     @Override
     47     protected void onCreate(Bundle savedInstanceState) {
     48         super.onCreate(savedInstanceState);
     49 
     50         setContentView(R.layout.main_layout);
     51 
     52         // Initialize UI
     53         mBitmapIn = loadBitmap(R.drawable.data);
     54         mBitmapsOut = new Bitmap[NUM_BITMAPS];
     55         for (int i = 0; i < NUM_BITMAPS; ++i) {
     56             mBitmapsOut[i] = Bitmap.createBitmap(mBitmapIn.getWidth(),
     57                     mBitmapIn.getHeight(), mBitmapIn.getConfig());
     58         }
     59 
     60         mImageView = (ImageView) findViewById(R.id.imageView);
     61         mImageView.setImageBitmap(mBitmapsOut[mCurrentBitmap]);
     62         mCurrentBitmap += (mCurrentBitmap + 1) % NUM_BITMAPS;
     63 
     64         SeekBar seekbar = (SeekBar) findViewById(R.id.seekBar1);
     65         seekbar.setProgress(50);
     66         seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
     67             public void onProgressChanged(SeekBar seekBar, int progress,
     68                                           boolean fromUser) {
     69                 float max = 2.0f;
     70                 float min = 0.0f;
     71                 float f = (float) ((max - min) * (progress / 100.0) + min);
     72                 updateImage(f);
     73             }
     74 
     75             @Override
     76             public void onStartTrackingTouch(SeekBar seekBar) {
     77             }
     78 
     79             @Override
     80             public void onStopTrackingTouch(SeekBar seekBar) {
     81             }
     82         });
     83 
     84         // Create renderScript
     85         createScript();
     86 
     87         // Invoke renderScript kernel and update imageView
     88         updateImage(1.0f);
     89     }
     90 
     91     /**
     92      * Initialize RenderScript.
     93      *
     94      * <p>In the sample, it creates RenderScript kernel that performs saturation manipulation.</p>
     95      */
     96     private void createScript() {
     97         // Initialize RS
     98         RenderScript rs = RenderScript.create(this);
     99 
    100         // Allocate buffers
    101         mInAllocation = Allocation.createFromBitmap(rs, mBitmapIn);
    102         mOutAllocations = new Allocation[NUM_BITMAPS];
    103         for (int i = 0; i < NUM_BITMAPS; ++i) {
    104             mOutAllocations[i] = Allocation.createFromBitmap(rs, mBitmapsOut[i]);
    105         }
    106 
    107         // Load script
    108         mScript = new ScriptC_saturation(rs);
    109     }
    110 
    111     /*
    112      * In the AsyncTask, it invokes RenderScript intrinsics to do a filtering.
    113      * After the filtering is done, an operation blocks at Allocation.copyTo() in AsyncTask thread.
    114      * Once all operation is finished at onPostExecute() in UI thread, it can invalidate and update
    115      * ImageView UI.
    116      */
    117     private class RenderScriptTask extends AsyncTask<Float, Void, Integer> {
    118         Boolean issued = false;
    119 
    120         protected Integer doInBackground(Float... values) {
    121             int index = -1;
    122             if (!isCancelled()) {
    123                 issued = true;
    124                 index = mCurrentBitmap;
    125 
    126                 // Set global variable in RS
    127                 mScript.set_saturationValue(values[0]);
    128 
    129                 // Invoke saturation filter kernel
    130                 mScript.forEach_saturation(mInAllocation, mOutAllocations[index]);
    131 
    132                 // Copy to bitmap and invalidate image view
    133                 mOutAllocations[index].copyTo(mBitmapsOut[index]);
    134                 mCurrentBitmap = (mCurrentBitmap + 1) % NUM_BITMAPS;
    135             }
    136             return index;
    137         }
    138 
    139         void updateView(Integer result) {
    140             if (result != -1) {
    141                 // Request UI update
    142                 mImageView.setImageBitmap(mBitmapsOut[result]);
    143                 mImageView.invalidate();
    144             }
    145         }
    146 
    147         protected void onPostExecute(Integer result) {
    148             updateView(result);
    149         }
    150 
    151         protected void onCancelled(Integer result) {
    152             if (issued) {
    153                 updateView(result);
    154             }
    155         }
    156     }
    157 
    158     /**
    159      * Invoke AsyncTask and cancel previous task. When AsyncTasks are piled up (typically in slow
    160      * device with heavy kernel), Only the latest (and already started) task invokes RenderScript
    161      * operation.
    162      */
    163     private void updateImage(final float f) {
    164         if (mCurrentTask != null) {
    165             mCurrentTask.cancel(false);
    166         }
    167         mCurrentTask = new RenderScriptTask();
    168         mCurrentTask.execute(f);
    169     }
    170 
    171     /**
    172      * Helper to load Bitmap from resource
    173      */
    174     private Bitmap loadBitmap(int resource) {
    175         final BitmapFactory.Options options = new BitmapFactory.Options();
    176         options.inPreferredConfig = Bitmap.Config.ARGB_8888;
    177         return BitmapFactory.decodeResource(getResources(), resource, options);
    178     }
    179 
    180 }
    181