| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.gallery3d.glrenderer; |
| |
| import com.android.gallery3d.ui.GLRoot; |
| import com.android.gallery3d.ui.GLRoot.OnGLIdleListener; |
| |
| import java.util.ArrayDeque; |
| |
| public class TextureUploader implements OnGLIdleListener { |
| private static final int INIT_CAPACITY = 64; |
| private static final int QUOTA_PER_FRAME = 1; |
| |
| private final ArrayDeque<UploadedTexture> mFgTextures = |
| new ArrayDeque<UploadedTexture>(INIT_CAPACITY); |
| private final ArrayDeque<UploadedTexture> mBgTextures = |
| new ArrayDeque<UploadedTexture>(INIT_CAPACITY); |
| private final GLRoot mGLRoot; |
| private volatile boolean mIsQueued = false; |
| |
| public TextureUploader(GLRoot root) { |
| mGLRoot = root; |
| } |
| |
| public synchronized void clear() { |
| while (!mFgTextures.isEmpty()) { |
| mFgTextures.pop().setIsUploading(false); |
| } |
| while (!mBgTextures.isEmpty()) { |
| mBgTextures.pop().setIsUploading(false); |
| } |
| } |
| |
| // caller should hold synchronized on "this" |
| private void queueSelfIfNeed() { |
| if (mIsQueued) return; |
| mIsQueued = true; |
| mGLRoot.addOnGLIdleListener(this); |
| } |
| |
| public synchronized void addBgTexture(UploadedTexture t) { |
| if (t.isContentValid()) return; |
| mBgTextures.addLast(t); |
| t.setIsUploading(true); |
| queueSelfIfNeed(); |
| } |
| |
| public synchronized void addFgTexture(UploadedTexture t) { |
| if (t.isContentValid()) return; |
| mFgTextures.addLast(t); |
| t.setIsUploading(true); |
| queueSelfIfNeed(); |
| } |
| |
| private int upload(GLCanvas canvas, ArrayDeque<UploadedTexture> deque, |
| int uploadQuota, boolean isBackground) { |
| while (uploadQuota > 0) { |
| UploadedTexture t; |
| synchronized (this) { |
| if (deque.isEmpty()) break; |
| t = deque.removeFirst(); |
| t.setIsUploading(false); |
| if (t.isContentValid()) continue; |
| |
| // this has to be protected by the synchronized block |
| // to prevent the inner bitmap get recycled |
| t.updateContent(canvas); |
| } |
| |
| // It will took some more time for a texture to be drawn for |
| // the first time. |
| // Thus, when scrolling, if a new column appears on screen, |
| // it may cause a UI jank even these textures are uploaded. |
| if (isBackground) t.draw(canvas, 0, 0); |
| --uploadQuota; |
| } |
| return uploadQuota; |
| } |
| |
| @Override |
| public boolean onGLIdle(GLCanvas canvas, boolean renderRequested, long dueTime) { |
| int uploadQuota = QUOTA_PER_FRAME; |
| uploadQuota = upload(canvas, mFgTextures, uploadQuota, false); |
| if (uploadQuota < QUOTA_PER_FRAME) mGLRoot.requestRender(); |
| upload(canvas, mBgTextures, uploadQuota, true); |
| synchronized (this) { |
| mIsQueued = !mFgTextures.isEmpty() || !mBgTextures.isEmpty(); |
| return mIsQueued; |
| } |
| } |
| } |