libgui: Fix handling of rotated surface damage

Incoming surface damage was not aware that the EGL implementation was
rotating buffers in response to SurfaceFlinger's transform hint. This
didn't affect all cases because the effect was to apply a 90 degree
rotation instead of a 270 degree rotation. For full-screen updates,
things more or less worked, but in other cases this caused corruption.

This fixes that by correctly undoing the effect of rotated buffers on
the incoming surface damage, and then passing that damage down
untouched to HWC.

Bug: 22068334
Change-Id: I226ecfc7a91fe2e16edd2aa6d9149f0d26b529d6
This commit is contained in:
Dan Stoza 2015-06-25 16:10:18 -07:00
parent 7a1b5d5dec
commit db4850c01f
2 changed files with 52 additions and 18 deletions

View File

@ -344,20 +344,61 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) { if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) {
input.setSurfaceDamage(Region::INVALID_REGION); input.setSurfaceDamage(Region::INVALID_REGION);
} else { } else {
// The surface damage was specified using the OpenGL ES convention of // Here we do two things:
// the origin being in the bottom-left corner. Here we flip to the // 1) The surface damage was specified using the OpenGL ES convention of
// convention that the rest of the system uses (top-left corner) by // the origin being in the bottom-left corner. Here we flip to the
// subtracting all top/bottom coordinates from the buffer height. // convention that the rest of the system uses (top-left corner) by
// subtracting all top/bottom coordinates from the buffer height.
// 2) If the buffer is coming in rotated (for example, because the EGL
// implementation is reacting to the transform hint coming back from
// SurfaceFlinger), the surface damage needs to be rotated the
// opposite direction, since it was generated assuming an unrotated
// buffer (the app doesn't know that the EGL implementation is
// reacting to the transform hint behind its back). The
// transformations in the switch statement below apply those
// complementary rotations (e.g., if 90 degrees, rotate 270 degrees).
int width = buffer->width;
int height = buffer->height; int height = buffer->height;
if ((mTransform ^ mStickyTransform) & NATIVE_WINDOW_TRANSFORM_ROT_90) { bool rotated90 = (mTransform ^ mStickyTransform) &
height = buffer->width; NATIVE_WINDOW_TRANSFORM_ROT_90;
if (rotated90) {
std::swap(width, height);
} }
Region flippedRegion; Region flippedRegion;
for (auto rect : mDirtyRegion) { for (auto rect : mDirtyRegion) {
auto top = height - rect.bottom; int left = rect.left;
auto bottom = height - rect.top; int right = rect.right;
Rect flippedRect{rect.left, top, rect.right, bottom}; int top = height - rect.bottom; // Flip from OpenGL convention
flippedRegion.orSelf(flippedRect); int bottom = height - rect.top; // Flip from OpenGL convention
switch (mTransform ^ mStickyTransform) {
case NATIVE_WINDOW_TRANSFORM_ROT_90: {
// Rotate 270 degrees
Rect flippedRect{top, width - right, bottom, width - left};
flippedRegion.orSelf(flippedRect);
break;
}
case NATIVE_WINDOW_TRANSFORM_ROT_180: {
// Rotate 180 degrees
Rect flippedRect{width - right, height - bottom,
width - left, height - top};
flippedRegion.orSelf(flippedRect);
break;
}
case NATIVE_WINDOW_TRANSFORM_ROT_270: {
// Rotate 90 degrees
Rect flippedRect{height - bottom, left,
height - top, right};
flippedRegion.orSelf(flippedRect);
break;
}
default: {
Rect flippedRect{left, top, right, bottom};
flippedRegion.orSelf(flippedRect);
break;
}
}
} }
input.setSurfaceDamage(flippedRegion); input.setSurfaceDamage(flippedRegion);

View File

@ -551,14 +551,7 @@ void Layer::setPerFrameData(const sp<const DisplayDevice>& hw,
const Transform& tr = hw->getTransform(); const Transform& tr = hw->getTransform();
Region visible = tr.transform(visibleRegion.intersect(hw->getViewport())); Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
layer.setVisibleRegionScreen(visible); layer.setVisibleRegionScreen(visible);
layer.setSurfaceDamage(surfaceDamageRegion);
// Pass full-surface damage down untouched
if (surfaceDamageRegion.isRect() &&
surfaceDamageRegion.getBounds() == Rect::INVALID_RECT) {
layer.setSurfaceDamage(surfaceDamageRegion);
} else {
layer.setSurfaceDamage(tr.transform(surfaceDamageRegion));
}
if (mSidebandStream.get()) { if (mSidebandStream.get()) {
layer.setSidebandStream(mSidebandStream); layer.setSidebandStream(mSidebandStream);