Add final crop implementation
Bug 26559810
Change-Id: Idaccd13cd625c92d18665ddecebdbb266ea365f3
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 42d0810..910aeae 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -118,6 +118,7 @@
mCurrentState.active.h = h;
mCurrentState.active.transform.set(0, 0);
mCurrentState.active.crop.makeInvalid();
+ mCurrentState.active.finalCrop.makeInvalid();
mCurrentState.z = 0;
#ifdef USE_HWC2
mCurrentState.alpha = 1.0f;
@@ -401,7 +402,14 @@
}
activeCrop = s.active.transform.transform(activeCrop);
- activeCrop.intersect(hw->getViewport(), &activeCrop);
+ if (!activeCrop.intersect(hw->getViewport(), &activeCrop)) {
+ activeCrop.clear();
+ }
+ if (!s.active.finalCrop.isEmpty()) {
+ if(!activeCrop.intersect(s.active.finalCrop, &activeCrop)) {
+ activeCrop.clear();
+ }
+ }
activeCrop = s.active.transform.inverse().transform(activeCrop);
// This needs to be here as transform.transform(Rect) computes the
@@ -410,72 +418,73 @@
// transform.inverse().transform(transform.transform(Rect)) != Rect
// in which case we need to make sure the final rect is clipped to the
// display bounds.
- activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop);
+ if (!activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop)) {
+ activeCrop.clear();
+ }
// subtract the transparent region and snap to the bounds
activeCrop = reduce(activeCrop, s.activeTransparentRegion);
- if (!activeCrop.isEmpty()) {
- // Transform the window crop to match the buffer coordinate system,
- // which means using the inverse of the current transform set on the
- // SurfaceFlingerConsumer.
- uint32_t invTransform = mCurrentTransform;
- if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
- /*
- * the code below applies the display's inverse transform to the buffer
- */
- uint32_t invTransformOrient = hw->getOrientationTransform();
- // calculate the inverse transform
- if (invTransformOrient & NATIVE_WINDOW_TRANSFORM_ROT_90) {
- invTransformOrient ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
- NATIVE_WINDOW_TRANSFORM_FLIP_H;
- // If the transform has been rotated the axis of flip has been swapped
- // so we need to swap which flip operations we are performing
- bool is_h_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) != 0;
- bool is_v_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) != 0;
- if (is_h_flipped != is_v_flipped) {
- invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
- NATIVE_WINDOW_TRANSFORM_FLIP_H;
- }
- }
- // and apply to the current transform
- invTransform = (Transform(invTransform) * Transform(invTransformOrient)).getOrientation();
- }
-
- int winWidth = s.active.w;
- int winHeight = s.active.h;
- if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
- // If the activeCrop has been rotate the ends are rotated but not
- // the space itself so when transforming ends back we can't rely on
- // a modification of the axes of rotation. To account for this we
- // need to reorient the inverse rotation in terms of the current
- // axes of rotation.
+ // Transform the window crop to match the buffer coordinate system,
+ // which means using the inverse of the current transform set on the
+ // SurfaceFlingerConsumer.
+ uint32_t invTransform = mCurrentTransform;
+ if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
+ /*
+ * the code below applies the display's inverse transform to the buffer
+ */
+ uint32_t invTransformOrient = hw->getOrientationTransform();
+ // calculate the inverse transform
+ if (invTransformOrient & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ invTransformOrient ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
+ NATIVE_WINDOW_TRANSFORM_FLIP_H;
+ // If the transform has been rotated the axis of flip has been swapped
+ // so we need to swap which flip operations we are performing
bool is_h_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) != 0;
bool is_v_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) != 0;
- if (is_h_flipped == is_v_flipped) {
+ if (is_h_flipped != is_v_flipped) {
invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
NATIVE_WINDOW_TRANSFORM_FLIP_H;
}
- winWidth = s.active.h;
- winHeight = s.active.w;
}
- const Rect winCrop = activeCrop.transform(
- invTransform, s.active.w, s.active.h);
-
- // below, crop is intersected with winCrop expressed in crop's coordinate space
- float xScale = crop.getWidth() / float(winWidth);
- float yScale = crop.getHeight() / float(winHeight);
-
- float insetL = winCrop.left * xScale;
- float insetT = winCrop.top * yScale;
- float insetR = (winWidth - winCrop.right ) * xScale;
- float insetB = (winHeight - winCrop.bottom) * yScale;
-
- crop.left += insetL;
- crop.top += insetT;
- crop.right -= insetR;
- crop.bottom -= insetB;
+ // and apply to the current transform
+ invTransform = (Transform(invTransform) * Transform(invTransformOrient)).getOrientation();
}
+
+ int winWidth = s.active.w;
+ int winHeight = s.active.h;
+ if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ // If the activeCrop has been rotate the ends are rotated but not
+ // the space itself so when transforming ends back we can't rely on
+ // a modification of the axes of rotation. To account for this we
+ // need to reorient the inverse rotation in terms of the current
+ // axes of rotation.
+ bool is_h_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) != 0;
+ bool is_v_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) != 0;
+ if (is_h_flipped == is_v_flipped) {
+ invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
+ NATIVE_WINDOW_TRANSFORM_FLIP_H;
+ }
+ winWidth = s.active.h;
+ winHeight = s.active.w;
+ }
+ const Rect winCrop = activeCrop.transform(
+ invTransform, s.active.w, s.active.h);
+
+ // below, crop is intersected with winCrop expressed in crop's coordinate space
+ float xScale = crop.getWidth() / float(winWidth);
+ float yScale = crop.getHeight() / float(winHeight);
+
+ float insetL = winCrop.left * xScale;
+ float insetT = winCrop.top * yScale;
+ float insetR = (winWidth - winCrop.right ) * xScale;
+ float insetB = (winHeight - winCrop.bottom) * yScale;
+
+ crop.left += insetL;
+ crop.top += insetT;
+ crop.right -= insetR;
+ crop.bottom -= insetB;
+
return crop;
}
@@ -537,10 +546,12 @@
Rect activeCrop(s.active.crop);
activeCrop = s.active.transform.transform(activeCrop);
#ifdef USE_HWC2
- activeCrop.intersect(displayDevice->getViewport(), &activeCrop);
+ if(!activeCrop.intersect(displayDevice->getViewport(), &activeCrop)) {
#else
- activeCrop.intersect(hw->getViewport(), &activeCrop);
+ if(!activeCrop.intersect(hw->getViewport(), &activeCrop)) {
#endif
+ activeCrop.clear();
+ }
activeCrop = s.active.transform.inverse().transform(activeCrop);
// This needs to be here as transform.transform(Rect) computes the
// transformed rect and then takes the bounding box of the result before
@@ -548,7 +559,9 @@
// transform.inverse().transform(transform.transform(Rect)) != Rect
// in which case we need to make sure the final rect is clipped to the
// display bounds.
- activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop);
+ if(!activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop)) {
+ activeCrop.clear();
+ }
// mark regions outside the crop as transparent
activeTransparentRegion.orSelf(Rect(0, 0, s.active.w, activeCrop.top));
activeTransparentRegion.orSelf(Rect(0, activeCrop.bottom,
@@ -559,8 +572,15 @@
s.active.w, activeCrop.bottom));
}
Rect frame(s.active.transform.transform(computeBounds(activeTransparentRegion)));
+ if (!s.active.finalCrop.isEmpty()) {
+ if(!frame.intersect(s.active.finalCrop, &frame)) {
+ frame.clear();
+ }
+ }
#ifdef USE_HWC2
- frame.intersect(displayDevice->getViewport(), &frame);
+ if (!frame.intersect(displayDevice->getViewport(), &frame)) {
+ frame.clear();
+ }
const Transform& tr(displayDevice->getTransform());
Rect transformedFrame = tr.transform(frame);
auto error = hwcLayer->setDisplayFrame(transformedFrame);
@@ -588,7 +608,9 @@
mName.string(), s.z, to_string(error).c_str(),
static_cast<int32_t>(error));
#else
- frame.intersect(hw->getViewport(), &frame);
+ if (!frame.intersect(hw->getViewport(), &frame)) {
+ frame.clear();
+ }
const Transform& tr(hw->getTransform());
layer.setFrame(tr.transform(frame));
layer.setCrop(computeCrop(hw));
@@ -782,6 +804,9 @@
Rect bounds = reduce(win, s.activeTransparentRegion);
Rect frame(s.active.transform.transform(bounds));
frame.intersect(displayDevice->getViewport(), &frame);
+ if (!s.active.finalCrop.isEmpty()) {
+ frame.intersect(s.active.finalCrop, &frame);
+ }
auto& displayTransform(displayDevice->getTransform());
auto position = displayTransform.transform(frame);
@@ -828,6 +853,9 @@
Rect bounds = reduce(win, s.activeTransparentRegion);
Rect frame(s.active.transform.transform(bounds));
frame.intersect(hw->getViewport(), &frame);
+ if (!s.active.finalCrop.isEmpty()) {
+ frame.intersect(s.active.finalCrop, &frame);
+ }
const Transform& tr(hw->getTransform());
return Rect(tr.transform(frame));
}
@@ -982,7 +1010,18 @@
* minimal value)? Or, we could make GL behave like HWC -- but this feel
* like more of a hack.
*/
- const Rect win(computeBounds());
+ Rect win(computeBounds());
+
+ if (!s.active.finalCrop.isEmpty()) {
+ win = s.active.transform.transform(win);
+ if (!win.intersect(s.active.finalCrop, &win)) {
+ win.clear();
+ }
+ win = s.active.transform.inverse().transform(win);
+ if (!win.intersect(computeBounds(), &win)) {
+ win.clear();
+ }
+ }
float left = float(win.left) / float(s.active.w);
float top = float(win.top) / float(s.active.h);
@@ -1116,12 +1155,26 @@
// local state
// ----------------------------------------------------------------------------
+static void boundPoint(vec2* point, const Rect& crop) {
+ if (point->x < crop.left) {
+ point->x = crop.left;
+ }
+ if (point->x > crop.right) {
+ point->x = crop.right;
+ }
+ if (point->y < crop.top) {
+ point->y = crop.top;
+ }
+ if (point->y > crop.bottom) {
+ point->y = crop.bottom;
+ }
+}
+
void Layer::computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh,
bool useIdentityTransform) const
{
const Layer::State& s(getDrawingState());
- const Transform tr(useIdentityTransform ?
- hw->getTransform() : hw->getTransform() * s.active.transform);
+ const Transform tr(hw->getTransform());
const uint32_t hw_h = hw->getHeight();
Rect win(s.active.w, s.active.h);
if (!s.active.crop.isEmpty()) {
@@ -1130,11 +1183,30 @@
// subtract the transparent region and snap to the bounds
win = reduce(win, s.activeTransparentRegion);
+ vec2 lt = vec2(win.left, win.top);
+ vec2 lb = vec2(win.left, win.bottom);
+ vec2 rb = vec2(win.right, win.bottom);
+ vec2 rt = vec2(win.right, win.top);
+
+ if (!useIdentityTransform) {
+ lt = s.active.transform.transform(lt);
+ lb = s.active.transform.transform(lb);
+ rb = s.active.transform.transform(rb);
+ rt = s.active.transform.transform(rt);
+ }
+
+ if (!s.active.finalCrop.isEmpty()) {
+ boundPoint(<, s.active.finalCrop);
+ boundPoint(&lb, s.active.finalCrop);
+ boundPoint(&rb, s.active.finalCrop);
+ boundPoint(&rt, s.active.finalCrop);
+ }
+
Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
- position[0] = tr.transform(win.left, win.top);
- position[1] = tr.transform(win.left, win.bottom);
- position[2] = tr.transform(win.right, win.bottom);
- position[3] = tr.transform(win.right, win.top);
+ position[0] = tr.transform(lt);
+ position[1] = tr.transform(lb);
+ position[2] = tr.transform(rb);
+ position[3] = tr.transform(rt);
for (size_t i=0 ; i<4 ; i++) {
position[i].y = hw_h - position[i].y;
}
@@ -1500,6 +1572,15 @@
setTransactionFlags(eTransactionNeeded);
return true;
}
+bool Layer::setFinalCrop(const Rect& crop) {
+ if (mCurrentState.requested.finalCrop == crop)
+ return false;
+ mCurrentState.sequence++;
+ mCurrentState.requested.finalCrop = crop;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
bool Layer::setLayerStack(uint32_t layerStack) {
if (mCurrentState.layerStack == layerStack)
@@ -1993,7 +2074,8 @@
sp<Client> client(mClientRef.promote());
result.appendFormat( " "
- "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
+ "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), "
+ "crop=(%4d,%4d,%4d,%4d), finalCrop=(%4d,%4d,%4d,%4d), "
"isOpaque=%1d, invalidate=%1d, "
#ifdef USE_HWC2
"alpha=%.3f, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
@@ -2004,6 +2086,8 @@
s.layerStack, s.z, s.active.transform.tx(), s.active.transform.ty(), s.active.w, s.active.h,
s.active.crop.left, s.active.crop.top,
s.active.crop.right, s.active.crop.bottom,
+ s.active.finalCrop.left, s.active.finalCrop.top,
+ s.active.finalCrop.right, s.active.finalCrop.bottom,
isOpaque(s), contentDirty,
s.alpha, s.flags,
s.active.transform[0][0], s.active.transform[0][1],