Wire up texture atlas

 Bug: 14590563

Change-Id: I2dffbc089dc801f5fb2d1c8fd38e1c71d160e110
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 5653066..17035b1 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -19,7 +19,11 @@
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.Trace;
+import android.util.Log;
 import android.util.TimeUtils;
 import android.view.Surface.OutOfResourcesException;
 import android.view.View.AttachInfo;
@@ -65,6 +69,8 @@
     private Choreographer mChoreographer;
 
     ThreadedRenderer(boolean translucent) {
+        AtlasInitializer.sInstance.init();
+
         long rootNodePtr = nCreateRootRenderNode();
         mRootNode = RenderNode.adopt(rootNodePtr);
         mRootNode.setClipToBounds(false);
@@ -292,8 +298,43 @@
         }
     }
 
-    /** @hide */
-    public static native void postToRenderThread(Runnable runnable);
+    private static class AtlasInitializer {
+        static AtlasInitializer sInstance = new AtlasInitializer();
+
+        private boolean mInitialized = false;
+
+        private AtlasInitializer() {}
+
+        synchronized void init() {
+            if (mInitialized) return;
+            IBinder binder = ServiceManager.getService("assetatlas");
+            if (binder == null) return;
+
+            IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
+            try {
+                if (atlas.isCompatible(android.os.Process.myPpid())) {
+                    GraphicBuffer buffer = atlas.getBuffer();
+                    if (buffer != null) {
+                        long[] map = atlas.getMap();
+                        if (map != null) {
+                            nSetAtlas(buffer, map);
+                            mInitialized = true;
+                        }
+                        // If IAssetAtlas is not the same class as the IBinder
+                        // we are using a remote service and we can safely
+                        // destroy the graphic buffer
+                        if (atlas.getClass() != binder.getClass()) {
+                            buffer.destroy();
+                        }
+                    }
+                }
+            } catch (RemoteException e) {
+                Log.w(LOG_TAG, "Could not acquire atlas", e);
+            }
+        }
+    }
+
+    private static native void nSetAtlas(GraphicBuffer buffer, long[] map);
 
     private static native long nCreateRootRenderNode();
     private static native long nCreateProxy(boolean translucent, long rootRenderNode);
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index cdd036e..d130a6d 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -26,8 +26,11 @@
 #include <android_runtime/android_view_Surface.h>
 #include <system/window.h>
 
+#include "android_view_GraphicBuffer.h"
+
 #include <Animator.h>
 #include <RenderNode.h>
+#include <renderthread/CanvasContext.h>
 #include <renderthread/RenderProxy.h>
 #include <renderthread/RenderTask.h>
 #include <renderthread/RenderThread.h>
@@ -67,6 +70,26 @@
     jobject mRunnable;
 };
 
+class SetAtlasTask : public RenderTask {
+public:
+    SetAtlasTask(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size)
+            : mBuffer(buffer)
+            , mMap(map)
+            , mMapSize(size) {
+    }
+
+    virtual void run() {
+        CanvasContext::setTextureAtlas(mBuffer, mMap, mMapSize);
+        mMap = 0;
+        delete this;
+    }
+
+private:
+    sp<GraphicBuffer> mBuffer;
+    int64_t* mMap;
+    size_t mMapSize;
+};
+
 class OnFinishedEvent {
 public:
     OnFinishedEvent(BaseAnimator* animator, AnimationListener* listener)
@@ -127,9 +150,18 @@
     std::vector<OnFinishedEvent> mOnFinishedEvents;
 };
 
-static void android_view_ThreadedRenderer_postToRenderThread(JNIEnv* env, jobject clazz,
-        jobject jrunnable) {
-    RenderTask* task = new JavaTask(env, jrunnable);
+static void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz,
+        jobject graphicBuffer, jlongArray atlasMapArray) {
+    sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer);
+    jsize len = env->GetArrayLength(atlasMapArray);
+    if (len <= 0) {
+        ALOGW("Failed to initialize atlas, invalid map length: %d", len);
+        return;
+    }
+    int64_t* map = new int64_t[len];
+    env->GetLongArrayRegion(atlasMapArray, 0, len, map);
+
+    SetAtlasTask* task = new SetAtlasTask(buffer, map, len);
     RenderThread::getInstance().queue(task);
 }
 
@@ -275,7 +307,7 @@
 
 static JNINativeMethod gMethods[] = {
 #ifdef USE_OPENGL_RENDERER
-    { "postToRenderThread", "(Ljava/lang/Runnable;)V",   (void*) android_view_ThreadedRenderer_postToRenderThread },
+    { "nSetAtlas", "(Landroid/view/GraphicBuffer;[J)V",   (void*) android_view_ThreadedRenderer_setAtlas },
     { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
     { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
     { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 5a23158..5754536 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -98,6 +98,8 @@
 
     bool enableDirtyRegions(EGLSurface surface);
 
+    void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize);
+
 private:
     GlobalContext();
     // GlobalContext is never destroyed, method is purposely not implemented
@@ -118,6 +120,10 @@
     bool mCanSetDirtyRegions;
 
     EGLSurface mCurrentSurface;
+
+    sp<GraphicBuffer> mAtlasBuffer;
+    int64_t* mAtlasMap;
+    size_t mAtlasMapSize;
 };
 
 GlobalContext* GlobalContext::sContext = 0;
@@ -135,7 +141,9 @@
         , mEglContext(EGL_NO_CONTEXT)
         , mPBufferSurface(EGL_NO_SURFACE)
         , mRequestDirtyRegions(load_dirty_regions_property())
-        , mCurrentSurface(EGL_NO_SURFACE) {
+        , mCurrentSurface(EGL_NO_SURFACE)
+        , mAtlasMap(NULL)
+        , mAtlasMapSize(0) {
     mCanSetDirtyRegions = mRequestDirtyRegions;
     ALOGD("Render dirty regions requested: %s", mRequestDirtyRegions ? "true" : "false");
 }
@@ -201,9 +209,28 @@
         "Failed to create context, error = %s", egl_error_str());
 }
 
+void GlobalContext::setTextureAtlas(const sp<GraphicBuffer>& buffer,
+        int64_t* map, size_t mapSize) {
+
+    // Already initialized
+    if (mAtlasBuffer.get()) {
+        ALOGW("Multiple calls to setTextureAtlas!");
+        delete map;
+        return;
+    }
+
+    mAtlasBuffer = buffer;
+    mAtlasMap = map;
+    mAtlasMapSize = mapSize;
+
+    if (hasContext()) {
+        usePBufferSurface();
+        initAtlas();
+    }
+}
+
 void GlobalContext::initAtlas() {
-    // TODO implement
-    // For now just run without an atlas
+    Caches::getInstance().assetAtlas.init(mAtlasBuffer, mAtlasMap, mAtlasMapSize);
 }
 
 void GlobalContext::usePBufferSurface() {
@@ -533,6 +560,11 @@
     }
 }
 
+void CanvasContext::setTextureAtlas(const sp<GraphicBuffer>& buffer,
+        int64_t* map, size_t mapSize) {
+    GlobalContext::get()->setTextureAtlas(buffer, map, mapSize);
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index dcb9858..a793d42 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -70,6 +70,9 @@
     Layer* createRenderLayer(int width, int height);
     Layer* createTextureLayer();
 
+    ANDROID_API static void setTextureAtlas(const sp<GraphicBuffer>& buffer,
+            int64_t* map, size_t mapSize);
+
 private:
     void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
     void prepareTree(TreeInfo& info);