Home | History | Annotate | Download | only in glrenderer
      1 /*
      2  * Copyright (C) 2012 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.android.gallery3d.glrenderer;
     18 
     19 import com.android.gallery3d.ui.GLRoot;
     20 import com.android.gallery3d.ui.GLRoot.OnGLIdleListener;
     21 
     22 import java.util.ArrayDeque;
     23 
     24 public class TextureUploader implements OnGLIdleListener {
     25     private static final int INIT_CAPACITY = 64;
     26     private static final int QUOTA_PER_FRAME = 1;
     27 
     28     private final ArrayDeque<UploadedTexture> mFgTextures =
     29             new ArrayDeque<UploadedTexture>(INIT_CAPACITY);
     30     private final ArrayDeque<UploadedTexture> mBgTextures =
     31             new ArrayDeque<UploadedTexture>(INIT_CAPACITY);
     32     private final GLRoot mGLRoot;
     33     private volatile boolean mIsQueued = false;
     34 
     35     public TextureUploader(GLRoot root) {
     36         mGLRoot = root;
     37     }
     38 
     39     public synchronized void clear() {
     40         while (!mFgTextures.isEmpty()) {
     41             mFgTextures.pop().setIsUploading(false);
     42         }
     43         while (!mBgTextures.isEmpty()) {
     44             mBgTextures.pop().setIsUploading(false);
     45         }
     46     }
     47 
     48     // caller should hold synchronized on "this"
     49     private void queueSelfIfNeed() {
     50         if (mIsQueued) return;
     51         mIsQueued = true;
     52         mGLRoot.addOnGLIdleListener(this);
     53     }
     54 
     55     public synchronized void addBgTexture(UploadedTexture t) {
     56         if (t.isContentValid()) return;
     57         mBgTextures.addLast(t);
     58         t.setIsUploading(true);
     59         queueSelfIfNeed();
     60     }
     61 
     62     public synchronized void addFgTexture(UploadedTexture t) {
     63         if (t.isContentValid()) return;
     64         mFgTextures.addLast(t);
     65         t.setIsUploading(true);
     66         queueSelfIfNeed();
     67     }
     68 
     69     private int upload(GLCanvas canvas, ArrayDeque<UploadedTexture> deque,
     70             int uploadQuota, boolean isBackground) {
     71         while (uploadQuota > 0) {
     72             UploadedTexture t;
     73             synchronized (this) {
     74                 if (deque.isEmpty()) break;
     75                 t = deque.removeFirst();
     76                 t.setIsUploading(false);
     77                 if (t.isContentValid()) continue;
     78 
     79                 // this has to be protected by the synchronized block
     80                 // to prevent the inner bitmap get recycled
     81                 t.updateContent(canvas);
     82             }
     83 
     84             // It will took some more time for a texture to be drawn for
     85             // the first time.
     86             // Thus, when scrolling, if a new column appears on screen,
     87             // it may cause a UI jank even these textures are uploaded.
     88             if (isBackground) t.draw(canvas, 0, 0);
     89             --uploadQuota;
     90         }
     91         return uploadQuota;
     92     }
     93 
     94     @Override
     95     public boolean onGLIdle(GLCanvas canvas, boolean renderRequested) {
     96         int uploadQuota = QUOTA_PER_FRAME;
     97         uploadQuota = upload(canvas, mFgTextures, uploadQuota, false);
     98         if (uploadQuota < QUOTA_PER_FRAME) mGLRoot.requestRender();
     99         upload(canvas, mBgTextures, uploadQuota, true);
    100         synchronized (this) {
    101             mIsQueued = !mFgTextures.isEmpty() || !mBgTextures.isEmpty();
    102             return mIsQueued;
    103         }
    104     }
    105 }
    106