Respect buffer source crop in client composition.
Previously only the SurfaceControl crop was respected, which causes a
discrepancy with HWC, since HWC recevies a crop that is intersected with
the crop provided by BufferQueue.
Bug: 122171389
Change-Id: Ie83fd30369ddd93703027c9577292eeb6f3fe110
Test: adb screenrecord
Test: Repro steps in b/122171389 no longer repro.
Test: adb screencap
Test: 4k youtube playback, fullscreen + rotations
Test: virtual display simulation
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 4eafeac..164a3a6 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -624,16 +624,19 @@
* minimal value)? Or, we could make GL behave like HWC -- but this feel
* like more of a hack.
*/
- const Rect bounds{computeBounds()}; // Rounds from FloatRect
- Rect win = bounds;
- const int bufferWidth = getBufferSize(s).getWidth();
- const int bufferHeight = getBufferSize(s).getHeight();
+ // Convert to Rect so that bounds are clipped to integers.
+ const Rect win{computeCrop(Rect::INVALID_RECT)};
+ // computeCrop() returns the cropping rectangle in buffer space, so we
+ // shouldn't use getBufferSize() since that may return a rectangle specified
+ // in layer space. Otherwise we may compute incorrect texture coordinates.
+ const float bufWidth = float(mActiveBuffer->getWidth());
+ const float bufHeight = float(mActiveBuffer->getHeight());
- const float left = float(win.left) / float(bufferWidth);
- const float top = float(win.top) / float(bufferHeight);
- const float right = float(win.right) / float(bufferWidth);
- const float bottom = float(win.bottom) / float(bufferHeight);
+ const float left = win.left / bufWidth;
+ const float top = win.top / bufHeight;
+ const float right = win.right / bufWidth;
+ const float bottom = win.bottom / bufHeight;
// TODO: we probably want to generate the texture coords with the mesh
// here we assume that we only have 4 vertices
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index d1b1697..aecde9f 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -39,7 +39,7 @@
bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
protected:
- FloatRect computeCrop(const sp<const DisplayDevice>& /*display*/) const override { return {}; }
+ FloatRect computeCrop(const Rect& /*windowbounds*/) const override { return {}; }
};
} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3f2d10a..ee49610 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -380,7 +380,7 @@
return size;
}
-Rect Layer::computeInitialCrop(const sp<const DisplayDevice>& display) const {
+Rect Layer::computeInitialCrop(const Rect& windowBounds) const {
// the crop is the area of the window that gets cropped, but not
// scaled in any ways.
const State& s(getDrawingState());
@@ -391,12 +391,17 @@
// pixels in the buffer.
FloatRect activeCropFloat = computeBounds();
- ui::Transform t = getTransform();
- // Transform to screen space.
- activeCropFloat = t.transform(activeCropFloat);
- activeCropFloat = activeCropFloat.intersect(display->getViewport().toFloatRect());
- // Back to layer space to work with the content crop.
- activeCropFloat = t.inverse().transform(activeCropFloat);
+
+ // If we have valid window boundaries then we need to crop to the window
+ // boundaries in layer space.
+ if (windowBounds.isValid()) {
+ const ui::Transform t = getTransform();
+ // Transform to screen space.
+ activeCropFloat = t.transform(activeCropFloat);
+ activeCropFloat = activeCropFloat.intersect(windowBounds.toFloatRect());
+ // Back to layer space to work with the content crop.
+ activeCropFloat = t.inverse().transform(activeCropFloat);
+ }
// This needs to be here as transform.transform(Rect) computes the
// transformed rect and then takes the bounding box of the result before
// returning. This means
@@ -426,7 +431,7 @@
cropCoords[3] = vec2(win.right, win.top);
}
-FloatRect Layer::computeCrop(const sp<const DisplayDevice>& display) const {
+FloatRect Layer::computeCrop(const Rect& windowBounds) const {
// the content crop is the area of the content that gets scaled to the
// layer's size. This is in buffer space.
FloatRect crop = getContentCrop().toFloatRect();
@@ -434,7 +439,7 @@
// In addition there is a WM-specified crop we pull from our drawing state.
const State& s(getDrawingState());
- Rect activeCrop = computeInitialCrop(display);
+ Rect activeCrop = computeInitialCrop(windowBounds);
Rect bufferSize = getBufferSize(s);
// Transform the window crop to match the buffer coordinate system,
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2e75088..7bc7a82 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -671,12 +671,22 @@
uint32_t getEffectiveUsage(uint32_t usage) const;
- virtual FloatRect computeCrop(const sp<const DisplayDevice>& display) const;
+ // Computes the crop applied to this layer. windowBounds is the boundary of
+ // layer-stack space, so the cropping rectangle will be clipped to those
+ // bounds in that space. The crop rectangle is returned in buffer space. If
+ // windowBounds is invalid, then it is ignored.
+ virtual FloatRect computeCrop(const Rect& windowBounds) const;
+
+ // See the above method, but pulls the window boundaries from the display.
+ FloatRect computeCrop(const sp<const DisplayDevice>& display) const {
+ return computeCrop(display->getViewport());
+ }
// Compute the initial crop as specified by parent layers and the
// SurfaceControl for this layer. Does not include buffer crop from the
// IGraphicBufferProducer client, as that should not affect child clipping.
// Returns in screen space.
- Rect computeInitialCrop(const sp<const DisplayDevice>& display) const;
+ Rect computeInitialCrop(const Rect& windowBounds) const;
+
/**
* Setup rounded corners coordinates of this layer, taking into account the layer bounds and
* crop coordinates, transforming them into layer space.