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