public synchronized void addTexture(TiledTexture t) {
      if (t.isReady()) return;
      mTextures.addLast(t);

      if (mIsQueued) return;
      mIsQueued = true;
      mGlRoot.addOnGLIdleListener(this);
    }
    @Override
    public boolean onGLIdle(GLCanvas canvas, boolean renderRequested) {
      ArrayDeque<TiledTexture> deque = mTextures;
      synchronized (this) {
        long now = SystemClock.uptimeMillis();
        long dueTime = now + UPLOAD_TILE_LIMIT;
        while (now < dueTime && !deque.isEmpty()) {
          TiledTexture t = deque.peekFirst();
          if (t.uploadNextTile(canvas)) {
            deque.removeFirst();
            mGlRoot.requestRender();
          }
          now = SystemClock.uptimeMillis();
        }
        mIsQueued = !mTextures.isEmpty();

        // return true to keep this listener in the queue
        return mIsQueued;
      }
    }