OSDN Git Service

Early rejection on shadows which are outside of the clip bound.
authorztenghui <ztenghui@google.com>
Wed, 19 Mar 2014 00:25:49 +0000 (17:25 -0700)
committerztenghui <ztenghui@google.com>
Thu, 20 Mar 2014 22:25:47 +0000 (15:25 -0700)
All the computations are estimated using bounding box.
TODO: Spot shadow could have more accurate but also more expensive methods, we need
more experiments to decide.

Change-Id: I9c10c419576cee55daf0f9f278b0db78cb847447

libs/hwui/OpenGLRenderer.cpp
libs/hwui/Rect.h
libs/hwui/ShadowTessellator.cpp
libs/hwui/ShadowTessellator.h

index cb8155b..cdd789d 100644 (file)
@@ -3226,11 +3226,13 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& c
     const int casterVertexCount = casterVertices2d.size();
     Vector3 casterPolygon[casterVertexCount];
     float minZ = FLT_MAX;
+    float maxZ = -FLT_MAX;
     for (int i = 0; i < casterVertexCount; i++) {
         const Vertex& point2d = casterVertices2d[i];
         casterPolygon[i] = Vector3(point2d.x, point2d.y, 0);
         mapPointFakeZ(casterPolygon[i], casterTransformXY, casterTransformZ);
         minZ = fmin(minZ, casterPolygon[i].z);
+        maxZ = fmax(maxZ, casterPolygon[i].z);
     }
 
     // map the centroid of the caster into 3d
@@ -3248,6 +3250,15 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& c
         }
         centroid3d.z += casterLift;
     }
+
+    // Check whether we want to draw the shadow at all by checking the caster's
+    // bounds against clip.
+    // We only have ortho projection, so we can just ignore the Z in caster for
+    // simple rejection calculation.
+    Rect localClip = mSnapshot->getLocalClip();
+    Rect casterBounds(casterOutline->getBounds());
+    casterTransformXY.mapRect(casterBounds);
+
     bool isCasterOpaque = (casterAlpha == 1.0f);
     // draw caster's shadows
     if (mCaches.propertyAmbientShadowStrength > 0) {
@@ -3255,7 +3266,7 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& c
         VertexBuffer ambientShadowVertexBuffer;
         VertexBufferMode vertexBufferMode = ShadowTessellator::tessellateAmbientShadow(
                 isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
-                ambientShadowVertexBuffer);
+                casterBounds, localClip, maxZ, ambientShadowVertexBuffer);
         drawVertexBuffer(vertexBufferMode, ambientShadowVertexBuffer, &paint);
     }
 
@@ -3266,7 +3277,8 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& c
                 mCaches.propertyLightPosYScale, mCaches.propertyLightPosZScale);
         VertexBufferMode vertexBufferMode = ShadowTessellator::tessellateSpotShadow(
                 isCasterOpaque, casterPolygon, casterVertexCount, lightPosScale,
-                *currentTransform(), getWidth(), getHeight(), spotShadowVertexBuffer);
+                *currentTransform(), getWidth(), getHeight(), casterBounds, localClip,
+                spotShadowVertexBuffer);
         drawVertexBuffer(vertexBufferMode, spotShadowVertexBuffer, &paint);
     }
 
index c230149..0083b77 100644 (file)
@@ -18,6 +18,7 @@
 #define ANDROID_HWUI_RECT_H
 
 #include <cmath>
+#include <SkRect.h>
 
 #include <utils/Log.h>
 
@@ -68,6 +69,13 @@ public:
             bottom(height) {
     }
 
+    inline Rect(const SkRect& rect):
+            left(rect.fLeft),
+            top(rect.fTop),
+            right(rect.fRight),
+            bottom(rect.fBottom) {
+    }
+
     friend int operator==(const Rect& a, const Rect& b) {
         return !memcmp(&a, &b, sizeof(a));
     }
index 771904a..4d0edfb 100644 (file)
@@ -35,7 +35,8 @@ static inline T max(T a, T b) {
 
 VertexBufferMode ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque,
         const Vector3* casterPolygon, int casterVertexCount,
-        const Vector3& centroid3d, VertexBuffer& shadowVertexBuffer) {
+        const Vector3& centroid3d, const Rect& casterBounds,
+        const Rect& localClip, float maxZ, VertexBuffer& shadowVertexBuffer) {
     ATRACE_CALL();
 
     // A bunch of parameters to tweak the shadow.
@@ -43,6 +44,16 @@ VertexBufferMode ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque,
     const float heightFactor = 1.0f / 128;
     const float geomFactor = 64;
 
+    Rect ambientShadowBounds(casterBounds);
+    ambientShadowBounds.outset(maxZ * geomFactor * heightFactor);
+
+    if (!localClip.intersects(ambientShadowBounds)) {
+#if DEBUG_SHADOW
+        ALOGD("Ambient shadow is out of clip rect!");
+#endif
+        return kVertexBufferMode_OnePolyRingShadow;
+    }
+
     return AmbientShadow::createAmbientShadow(isCasterOpaque, casterPolygon,
             casterVertexCount, centroid3d, heightFactor, geomFactor,
             shadowVertexBuffer);
@@ -52,7 +63,8 @@ VertexBufferMode ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque,
 VertexBufferMode ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
         const Vector3* casterPolygon, int casterVertexCount,
         const Vector3& lightPosScale, const mat4& receiverTransform,
-        int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer) {
+        int screenWidth, int screenHeight, const Rect& casterBounds,
+        const Rect& localClip, VertexBuffer& shadowVertexBuffer) {
     ATRACE_CALL();
 
     // A bunch of parameters to tweak the shadow.
@@ -73,6 +85,18 @@ VertexBufferMode ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
     const float lightSize = maximal / 4;
     const int lightVertexCount = 8;
 
+    // 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);
+    lightRect.unionWith(localClip);
+    if (!lightRect.intersects(casterBounds)) {
+#if DEBUG_SHADOW
+        ALOGD("Spot shadow is out of clip rect!");
+#endif
+        return kVertexBufferMode_OnePolyRingShadow;
+    }
+
     VertexBufferMode mode = SpotShadow::createSpotShadow(isCasterOpaque,
             casterPolygon, casterVertexCount, lightCenter, lightSize,
             lightVertexCount, shadowVertexBuffer);
index ab039fa..ff3de74 100644 (file)
@@ -66,12 +66,14 @@ class ShadowTessellator {
 public:
     static VertexBufferMode tessellateAmbientShadow(bool isCasterOpaque,
             const Vector3* casterPolygon, int casterVertexCount,
-            const Vector3& centroid3d, VertexBuffer& shadowVertexBuffer);
+            const Vector3& centroid3d,  const Rect& casterBounds,
+            const Rect& localClip, float maxZ, VertexBuffer& shadowVertexBuffer);
 
     static VertexBufferMode tessellateSpotShadow(bool isCasterOpaque,
             const Vector3* casterPolygon, int casterVertexCount,
             const Vector3& lightPosScale, const mat4& receiverTransform,
-            int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer);
+            int screenWidth, int screenHeight, const Rect& casterBounds,
+            const Rect& localClip, VertexBuffer& shadowVertexBuffer);
 
     static void generateShadowIndices(uint16_t*  shadowIndices);