Define light position (using new lighting spec) in Java

Also updates the relative shadow strengths.

Change-Id: I6cac7275d38df98aea9f0dda463cd7207102986a
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 9601a8d..6dd7c00 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -1097,9 +1097,10 @@
     }
 
     @Override
-    void setup(int width, int height) {
+    void setup(int width, int height, float lightX, float lightY, float lightZ, float lightRadius) {
         if (validate()) {
             mCanvas.setViewport(width, height);
+            mCanvas.initializeLight(lightX, lightY, lightZ, lightRadius);
             mWidth = width;
             mHeight = height;
         }
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index e366697..a902ce7 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -273,12 +273,16 @@
      *
      * @param width Width of the drawing surface.
      * @param height Height of the drawing surface.
+     * @param lightX X position of the shadow casting light
+     * @param lightY Y position of the shadow casting light
+     * @param lightZ Z position of the shadow casting light
+     * @param lightRadius radius of the shadow casting light
      */
-    abstract void setup(int width, int height);
+    abstract void setup(int width, int height, float lightX, float lightY, float lightZ, float lightRadius);
 
     /**
      * Gets the current width of the surface. This is the width that the surface
-     * was last set to in a call to {@link #setup(int, int)}.
+     * was last set to in a call to {@link #setup(int, int, float, float, float, float)}.
      *
      * @return the current width of the surface
      */
@@ -286,7 +290,7 @@
 
     /**
      * Gets the current height of the surface. This is the height that the surface
-     * was last set to in a call to {@link #setup(int, int)}.
+     * was last set to in a call to {@link #setup(int, int, float, float, float, float)}.
      *
      * @return the current width of the surface
      */
@@ -310,9 +314,6 @@
      * whenever system properties are modified. Implementations can use this
      * to trigger live updates of the renderer based on properties.
      *
-     * @param surface The surface to update with the new properties.
-     *                Can be null.
-     *
      * @return True if a property has changed.
      */
     abstract boolean loadSystemProperties();
@@ -443,17 +444,18 @@
      * @param width The width of the drawing surface.
      * @param height The height of the drawing surface.
      * @param surface The surface to hardware accelerate
+     * @param metrics The display metrics used to draw the output.
      *
      * @return true if the surface was initialized, false otherwise. Returning
      *         false might mean that the surface was already initialized.
      */
-    boolean initializeIfNeeded(int width, int height, Surface surface)
+    boolean initializeIfNeeded(int width, int height, Surface surface, DisplayMetrics metrics)
             throws OutOfResourcesException {
         if (isRequested()) {
             // We lost the gl context, so recreate it.
             if (!isEnabled()) {
                 if (initialize(surface)) {
-                    setup(width, height);
+                    setup(width, height, metrics);
                     return true;
                 }
             }
@@ -461,6 +463,14 @@
         return false;
     }
 
+    void setup(int width, int height, DisplayMetrics metrics) {
+        float lightX = width / 2.0f;
+        float lightY = -400 * metrics.density;
+        float lightZ = 800 * metrics.density;
+        float lightRadius = 800 * metrics.density;
+        setup(width, height, lightX, lightY, lightZ, lightRadius);
+    }
+
     /**
      * Optional, sets the name of the renderer. Useful for debugging purposes.
      *
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index afd9569..704d516 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -145,11 +145,11 @@
     }
 
     @Override
-    void setup(int width, int height) {
+    void setup(int width, int height, float lightX, float lightY, float lightZ, float lightRadius) {
         mWidth = width;
         mHeight = height;
         mRootNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
-        nSetup(mNativeProxy, width, height);
+        nSetup(mNativeProxy, width, height, lightX, lightY, lightZ, lightRadius);
     }
 
     @Override
@@ -348,10 +348,9 @@
     private static native boolean nInitialize(long nativeProxy, Surface window);
     private static native void nUpdateSurface(long nativeProxy, Surface window);
     private static native void nPauseSurface(long nativeProxy, Surface window);
-    private static native void nSetup(long nativeProxy, int width, int height);
+    private static native void nSetup(long nativeProxy, int width, int height,
+            float lightX, float lightY, float lightZ, float lightRadius);
     private static native void nSetOpaque(long nativeProxy, boolean opaque);
-    private static native void nSetDisplayListData(long nativeProxy, long displayList,
-            long newData);
     private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos,
             int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
     private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index eed6412..799a406 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -47,7 +47,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -1714,7 +1713,8 @@
                 if (hwInitialized ||
                         mWidth != mAttachInfo.mHardwareRenderer.getWidth() ||
                         mHeight != mAttachInfo.mHardwareRenderer.getHeight()) {
-                    mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
+                    mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight,
+                            mAttachInfo.mRootView.getResources().getDisplayMetrics());
                     if (!hwInitialized) {
                         mAttachInfo.mHardwareRenderer.invalidate(mSurface);
                         mFullRedrawNeeded = true;
@@ -2453,7 +2453,7 @@
 
                     try {
                         attachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
-                                mSurface);
+                                mSurface, attachInfo.mRootView.getResources().getDisplayMetrics());
                     } catch (OutOfResourcesException e) {
                         handleOutOfResourcesException(e);
                         return;
@@ -3151,7 +3151,8 @@
                             mFullRedrawNeeded = true;
                             try {
                                 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
-                                        mWidth, mHeight, mSurface);
+                                        mWidth, mHeight, mSurface,
+                                        mAttachInfo.mRootView.getResources().getDisplayMetrics());
                             } catch (OutOfResourcesException e) {
                                 Log.e(TAG, "OutOfResourcesException locking surface", e);
                                 try {
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 2c10212..48fb729 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -34,6 +34,7 @@
 #include <renderthread/RenderProxy.h>
 #include <renderthread/RenderTask.h>
 #include <renderthread/RenderThread.h>
+#include <Vector.h>
 
 namespace android {
 
@@ -223,10 +224,11 @@
     proxy->pauseSurface(window);
 }
 
-static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jint width, jint height) {
+static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
+        jint width, jint height,
+        jfloat lightX, jfloat lightY, jfloat lightZ, jfloat lightRadius) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    proxy->setup(width, height);
+    proxy->setup(width, height, Vector3(lightX, lightY, lightZ), lightRadius);
 }
 
 static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
@@ -316,7 +318,7 @@
     { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
     { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
     { "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface },
-    { "nSetup", "(JII)V", (void*) android_view_ThreadedRenderer_setup },
+    { "nSetup", "(JIIFFFF)V", (void*) android_view_ThreadedRenderer_setup },
     { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
     { "nSyncAndDrawFrame", "(JJIIII)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
     { "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface },
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 5b18623..d4ea7a9 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -236,8 +236,12 @@
      *
      * @hide
      */
-    public void setViewport(int width, int height) {
-    }
+    public void setViewport(int width, int height) {}
+
+    /**
+     * @hide
+     */
+    public void initializeLight(float lightX, float lightY, float lightZ, float lightRadius) {}
 
     /**
      * Return true if the device that the current layer draws into is opaque
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 43223ec..77ef637 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -688,8 +688,8 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void Caches::initTempProperties() {
-    propertyAmbientShadowStrength = 25;
-    propertySpotShadowStrength = 25;
+    propertyAmbientShadowStrength = 12;
+    propertySpotShadowStrength = 48;
 
     propertyLightDiameter = -1.0f;
     propertyLightPosY = -1.0f;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index a4bce3a..606c67e 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -56,10 +56,6 @@
     return data;
 }
 
-void DisplayListRenderer::setViewport(int width, int height) {
-    initializeViewport(width, height);
-}
-
 status_t DisplayListRenderer::prepareDirty(float left, float top,
         float right, float bottom, bool opaque) {
 
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 185179a..d814111 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -33,9 +33,6 @@
 // Defines
 ///////////////////////////////////////////////////////////////////////////////
 
-#define MIN_WRITER_SIZE 4096
-#define OP_MAY_BE_SKIPPED_MASK 0xff000000
-
 // Debug
 #if DEBUG_DISPLAY_LIST
     #define DISPLAY_LIST_LOGD(...) ALOGD(__VA_ARGS__)
@@ -68,7 +65,6 @@
 // ----------------------------------------------------------------------------
 // Frame state operations
 // ----------------------------------------------------------------------------
-    virtual void setViewport(int width, int height);
     virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
     virtual void finish();
     virtual void interrupt();
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index de2fcf4..6a2ef2a 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -214,7 +214,7 @@
     DeferStateStruct deferredState(*deferredList, *renderer,
             RenderNode::kReplayFlag_ClipChildren);
 
-    renderer->initializeViewport(width, height);
+    renderer->setViewport(width, height);
     renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
             dirtyRect.right, dirtyRect.bottom, !isBlend());
 
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index c82197c..df9aee5 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -39,10 +39,6 @@
 LayerRenderer::~LayerRenderer() {
 }
 
-void LayerRenderer::setViewport(int width, int height) {
-    initializeViewport(width, height);
-}
-
 status_t LayerRenderer::prepareDirty(float left, float top, float right, float bottom,
         bool opaque) {
     LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo());
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 40e461a..e79e7b8 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -47,7 +47,7 @@
     ANDROID_API LayerRenderer(Layer* layer);
     virtual ~LayerRenderer();
 
-    virtual void setViewport(int width, int height);
+    virtual void onViewportInitialized(int width, int height) { /* do nothing */ }
     virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
     virtual status_t clear(float left, float top, float right, float bottom, bool opaque);
     virtual void finish();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 826d988..691f1c9 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -161,9 +161,7 @@
 // Setup
 ///////////////////////////////////////////////////////////////////////////////
 
-void OpenGLRenderer::setViewport(int width, int height) {
-    initializeViewport(width, height);
-
+void OpenGLRenderer::onViewportInitialized() {
     glDisable(GL_DITHER);
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 
@@ -3240,7 +3238,7 @@
         VertexBuffer spotShadowVertexBuffer;
         VertexBufferMode vertexBufferMode = ShadowTessellator::tessellateSpotShadow(
                 isCasterOpaque, casterPolygon, casterVertexCount,
-                *currentTransform(), getWidth(), getHeight(), casterBounds, localClip,
+                *currentTransform(), mLightCenter, mLightRadius, casterBounds, localClip,
                 spotShadowVertexBuffer);
         drawVertexBuffer(vertexBufferMode, spotShadowVertexBuffer, &paint);
     }
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index f70ae58..c6d9071 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -131,7 +131,7 @@
 
     ANDROID_API void initProperties();
 
-    virtual void setViewport(int width, int height);
+    virtual void onViewportInitialized();
     virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
     virtual void finish();
     virtual void interrupt();
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index 57db816..e191a26 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -89,6 +89,14 @@
     virtual void setViewport(int width, int height) = 0;
 
     /**
+     * Sets the position and size of the spot shadow casting light.
+     *
+     * @param lightCenter The light's Y position, relative to the render target's top left
+     * @param lightRadius The light's radius
+     */
+    virtual void initializeLight(const Vector3& lightCenter, float lightRadius) = 0;
+
+    /**
      * Prepares the renderer to draw a frame. This method must be invoked
      * at the beginning of each frame. When this method is invoked, the
      * entire drawing surface is assumed to be redrawn.
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index 55b82e4..2f714a1 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -68,47 +68,40 @@
 
 VertexBufferMode ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
         const Vector3* casterPolygon, int casterVertexCount,
-        const mat4& receiverTransform,
-        int screenWidth, int screenHeight, const Rect& casterBounds,
-        const Rect& localClip, VertexBuffer& shadowVertexBuffer) {
+        const mat4& receiverTransform, const Vector3& lightCenter, int lightRadius,
+        const Rect& casterBounds, const Rect& localClip, VertexBuffer& shadowVertexBuffer) {
     ATRACE_CALL();
 
     Caches& caches = Caches::getInstance();
 
-    // A bunch of parameters to tweak the shadow.
-    // TODO: Allow some of these changable by debug settings or APIs.
-    int maximal = max(screenWidth, screenHeight);
-    Vector3 lightCenter(screenWidth * 0.5f, 0, maximal);
-
+    Vector3 adjustedLightCenter(lightCenter);
     if (CC_UNLIKELY(caches.propertyLightPosY > 0)) {
-        lightCenter.y = - caches.propertyLightPosY; // negated since this shifts up
+        adjustedLightCenter.y = - caches.propertyLightPosY; // negated since this shifts up
     }
     if (CC_UNLIKELY(caches.propertyLightPosZ > 0)) {
-        lightCenter.z = caches.propertyLightPosZ;
+        adjustedLightCenter.z = caches.propertyLightPosZ;
     }
 
-
 #if DEBUG_SHADOW
-    ALOGD("light center %f %f %f", lightCenter.x, lightCenter.y, lightCenter.z);
+    ALOGD("light center %f %f %f",
+            adjustedLightCenter.x, adjustedLightCenter.y, adjustedLightCenter.z);
 #endif
 
     // light position (because it's in local space) needs to compensate for receiver transform
     // TODO: should apply to light orientation, not just position
     Matrix4 reverseReceiverTransform;
     reverseReceiverTransform.loadInverse(receiverTransform);
-    reverseReceiverTransform.mapPoint3d(lightCenter);
+    reverseReceiverTransform.mapPoint3d(adjustedLightCenter);
 
-    float lightSize = maximal / 4;
     const int lightVertexCount = 8;
-
     if (CC_UNLIKELY(caches.propertyLightDiameter > 0)) {
-        lightSize = caches.propertyLightDiameter;
+        lightRadius = caches.propertyLightDiameter;
     }
 
     // Now light and caster are both in local space, we will check whether
     // the shadow is within the clip area.
-    Rect lightRect = Rect(lightCenter.x - lightSize, lightCenter.y - lightSize,
-            lightCenter.x + lightSize, lightCenter.y + lightSize);
+    Rect lightRect = Rect(adjustedLightCenter.x - lightRadius, adjustedLightCenter.y - lightRadius,
+            adjustedLightCenter.x + lightRadius, adjustedLightCenter.y + lightRadius);
     lightRect.unionWith(localClip);
     if (!lightRect.intersects(casterBounds)) {
 #if DEBUG_SHADOW
@@ -118,7 +111,7 @@
     }
 
     VertexBufferMode mode = SpotShadow::createSpotShadow(isCasterOpaque,
-            casterPolygon, casterVertexCount, lightCenter, lightSize,
+            casterPolygon, casterVertexCount, adjustedLightCenter, lightRadius,
             lightVertexCount, shadowVertexBuffer);
 
 #if DEBUG_SHADOW
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
index e5a3da1..a1606ad 100644
--- a/libs/hwui/ShadowTessellator.h
+++ b/libs/hwui/ShadowTessellator.h
@@ -73,9 +73,8 @@
 
     static VertexBufferMode tessellateSpotShadow(bool isCasterOpaque,
             const Vector3* casterPolygon, int casterVertexCount,
-            const mat4& receiverTransform,
-            int screenWidth, int screenHeight, const Rect& casterBounds,
-            const Rect& localClip, VertexBuffer& shadowVertexBuffer);
+            const mat4& receiverTransform, const Vector3& lightCenter, int lightRadius,
+            const Rect& casterBounds, const Rect& localClip, VertexBuffer& shadowVertexBuffer);
 
     static void generateShadowIndices(uint16_t*  shadowIndices);
 
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp
index 7d299f0..90039e9 100644
--- a/libs/hwui/StatefulBaseRenderer.cpp
+++ b/libs/hwui/StatefulBaseRenderer.cpp
@@ -25,7 +25,8 @@
 
 StatefulBaseRenderer::StatefulBaseRenderer() :
         mDirtyClip(false), mWidth(-1), mHeight(-1),
-        mSaveCount(1), mFirstSnapshot(new Snapshot), mSnapshot(mFirstSnapshot) {
+        mSaveCount(1), mFirstSnapshot(new Snapshot), mSnapshot(mFirstSnapshot),
+        mLightCenter(FLT_MIN, FLT_MIN, FLT_MIN), mLightRadius(FLT_MIN) {
 }
 
 void StatefulBaseRenderer::initializeSaveStack(float clipLeft, float clipTop,
@@ -37,10 +38,16 @@
     mSaveCount = 1;
 }
 
-void StatefulBaseRenderer::initializeViewport(int width, int height) {
+void StatefulBaseRenderer::setViewport(int width, int height) {
     mWidth = width;
     mHeight = height;
     mFirstSnapshot->initializeViewport(width, height);
+    onViewportInitialized();
+}
+
+void StatefulBaseRenderer::initializeLight(const Vector3& lightCenter, float lightRadius) {
+    mLightCenter = lightCenter;
+    mLightRadius = lightRadius;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h
index 2e7f279..057006b 100644
--- a/libs/hwui/StatefulBaseRenderer.h
+++ b/libs/hwui/StatefulBaseRenderer.h
@@ -48,10 +48,11 @@
     }
 
     /**
-     * Initialize the first snapshot, computing the projection matrix,
-     * and stores the dimensions of the render target.
+     * Initialize the first snapshot, computing the projection matrix, and stores the dimensions of
+     * the render target.
      */
-    void initializeViewport(int width, int height);
+    virtual void setViewport(int width, int height);
+    virtual void initializeLight(const Vector3& lightCenter, float lightRadius);
     void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom);
 
     // getters
@@ -124,6 +125,8 @@
      */
     virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {};
 
+    virtual void onViewportInitialized() {};
+
     inline const Rect* currentClipRect() const {
         return mSnapshot->clipRect;
     }
@@ -158,6 +161,9 @@
     // TODO: should become private, once hooks needed by OpenGLRenderer are added
     sp<Snapshot> mSnapshot;
 
+    Vector3 mLightCenter;
+    float mLightRadius;
+
 }; // class StatefulBaseRenderer
 
 }; // namespace uirenderer
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 48cd8fc..839ef91 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -410,9 +410,10 @@
     // and such to prevent from trying to render into this surface
 }
 
-void CanvasContext::setup(int width, int height) {
+void CanvasContext::setup(int width, int height, const Vector3& lightCenter, float lightRadius) {
     if (!mCanvas) return;
     mCanvas->setViewport(width, height);
+    mCanvas->initializeLight(lightCenter, lightRadius);
 }
 
 void CanvasContext::setOpaque(bool opaque) {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index a793d42..4232f27 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -51,7 +51,7 @@
     bool initialize(EGLNativeWindowType window);
     void updateSurface(EGLNativeWindowType window);
     void pauseSurface(EGLNativeWindowType window);
-    void setup(int width, int height);
+    void setup(int width, int height, const Vector3& lightCenter, float lightRadius);
     void setOpaque(bool opaque);
     void makeCurrent();
     void prepareDraw(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 82a2dbc..ef8e45b 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -38,6 +38,7 @@
 #define CREATE_BRIDGE2(name, a1, a2) CREATE_BRIDGE(name, a1,a2,,,,,,)
 #define CREATE_BRIDGE3(name, a1, a2, a3) CREATE_BRIDGE(name, a1,a2,a3,,,,,)
 #define CREATE_BRIDGE4(name, a1, a2, a3, a4) CREATE_BRIDGE(name, a1,a2,a3,a4,,,,)
+#define CREATE_BRIDGE5(name, a1, a2, a3, a4, a5) CREATE_BRIDGE(name, a1,a2,a3,a4,a5,,,)
 #define CREATE_BRIDGE(name, a1, a2, a3, a4, a5, a6, a7, a8) \
     typedef struct { \
         a1; a2; a3; a4; a5; a6; a7; a8; \
@@ -146,16 +147,19 @@
     postAndWait(task);
 }
 
-CREATE_BRIDGE3(setup, CanvasContext* context, int width, int height) {
-    args->context->setup(args->width, args->height);
+CREATE_BRIDGE5(setup, CanvasContext* context, int width, int height,
+        Vector3 lightCenter, int lightRadius) {
+    args->context->setup(args->width, args->height, args->lightCenter, args->lightRadius);
     return NULL;
 }
 
-void RenderProxy::setup(int width, int height) {
+void RenderProxy::setup(int width, int height, const Vector3& lightCenter, float lightRadius) {
     SETUP_TASK(setup);
     args->context = mContext;
     args->width = width;
     args->height = height;
+    args->lightCenter = lightCenter;
+    args->lightRadius = lightRadius;
     post(task);
 }
 
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 4a7e70a..4d3499e 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -66,7 +66,7 @@
     ANDROID_API bool initialize(const sp<ANativeWindow>& window);
     ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
     ANDROID_API void pauseSurface(const sp<ANativeWindow>& window);
-    ANDROID_API void setup(int width, int height);
+    ANDROID_API void setup(int width, int height, const Vector3& lightCenter, float lightRadius);
     ANDROID_API void setOpaque(bool opaque);
     ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos,
             int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);