diff options
| author | 2013-02-28 17:12:07 -0800 | |
|---|---|---|
| committer | 2013-02-28 18:43:04 -0800 | |
| commit | 3da1672acbe6a84f1d69f1e21096115c60826aea (patch) | |
| tree | c7b7fee89740714b0a8e61290db1cc069e02ac8d | |
| parent | a8bca8d84b559e7dcca010f7d6514333004020c7 (diff) | |
implement display projection clipping in h/w composer
- cropping to the projection's "viewport" is "simply"
accomplished by intersecting it with the window crop
expressed in layerstack space.
Bug: 7149437
Change-Id: I0e90b3f37945292314b5d78a8f134935967e8053
| -rw-r--r-- | services/surfaceflinger/LayerBase.cpp | 45 | ||||
| -rw-r--r-- | services/surfaceflinger/Transform.cpp | 38 | ||||
| -rw-r--r-- | services/surfaceflinger/Transform.h | 2 |
3 files changed, 80 insertions, 5 deletions
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp index 572e7c8913..db2b20eaaf 100644 --- a/services/surfaceflinger/LayerBase.cpp +++ b/services/surfaceflinger/LayerBase.cpp @@ -281,6 +281,14 @@ uint32_t LayerBase::getContentTransform() const { } Rect LayerBase::computeCrop(const sp<const DisplayDevice>& hw) const { + /* + * The way we compute the crop (aka. texture coordinates when we have a + * Layer) produces a different output from the GL code in + * drawWithOpenGL() due to HWC being limited to integers. The difference + * can be large if getContentTransform() contains a large scale factor. + * See comments in drawWithOpenGL() for more details. + */ + // the content crop is the area of the content that gets scaled to the // layer's size. Rect crop(getContentCrop()); @@ -288,7 +296,21 @@ Rect LayerBase::computeCrop(const sp<const DisplayDevice>& hw) const { // the active.crop is the area of the window that gets cropped, but not // scaled in any ways. const State& s(drawingState()); - Rect activeCrop(s.active.crop); + + // apply the projection's clipping to the window crop in + // layerstack space, and convert-back to layer space. + // if there are no window scaling (or content scaling) involved, + // this operation will map to full pixels in the buffer. + // NOTE: should we revert to GL composition if a scaling is involved + // since it cannot be represented in the HWC API? + Rect activeCrop(s.transform.transform(s.active.crop)); + activeCrop.intersect(hw->getViewport(), &activeCrop); + activeCrop = s.transform.inverse().transform(activeCrop); + + // paranoia: make sure the window-crop is constrained in the + // window's bounds + activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop); + 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 @@ -350,6 +372,7 @@ void LayerBase::setGeometry( // here we're guaranteed that the layer's transform preserves rects Rect frame(s.transform.transform(computeBounds())); + frame.intersect(hw->getViewport(), &frame); const Transform& tr(hw->getTransform()); layer.setFrame(tr.transform(frame)); layer.setCrop(computeCrop(hw)); @@ -464,10 +487,22 @@ void LayerBase::drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& GLfloat v; }; - Rect win(s.active.w, s.active.h); - if (!s.active.crop.isEmpty()) { - win.intersect(s.active.crop, &win); - } + + /* + * NOTE: the way we compute the texture coordinates here produces + * different results than when we take the HWC path -- in the later case + * the "source crop" is rounded to texel boundaries. + * This can produce significantly different results when the texture + * is scaled by a large amount. + * + * The GL code below is more logical (imho), and the difference with + * HWC is due to a limitation of the HWC API to integers -- a question + * is suspend is wether we should ignore this problem or revert to + * GL composition when a buffer scaling is applied (maybe with some + * minimal value)? Or, we could make GL behave like HWC -- but this feel + * like more of a hack. + */ + const Rect win(computeBounds()); GLfloat left = GLfloat(win.left) / GLfloat(s.active.w); GLfloat top = GLfloat(win.top) / GLfloat(s.active.h); diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp index aca90e016b..315720e1cf 100644 --- a/services/surfaceflinger/Transform.cpp +++ b/services/surfaceflinger/Transform.cpp @@ -298,6 +298,44 @@ uint32_t Transform::type() const return mType; } +Transform Transform::inverse() const { + // our 3x3 matrix is always of the form of a 2x2 transformation + // followed by a translation: T*M, therefore: + // (T*M)^-1 = M^-1 * T^-1 + Transform result; + if (mType <= TRANSLATE) { + // 1 0 x + // 0 1 y + // 0 0 1 + result = *this; + result.mMatrix[2][0] = -result.mMatrix[2][0]; + result.mMatrix[2][1] = -result.mMatrix[2][1]; + } else { + // a c x + // b d y + // 0 0 1 + const mat33& M(mMatrix); + const float a = M[0][0]; + const float b = M[1][0]; + const float c = M[0][1]; + const float d = M[1][1]; + const float x = M[2][0]; + const float y = M[2][1]; + + Transform R, T; + const float idet = 1.0 / (a*d - b*c); + R.mMatrix[0][0] = d*idet; R.mMatrix[0][1] = -c*idet; + R.mMatrix[1][0] = -b*idet; R.mMatrix[1][1] = a*idet; + R.mType = mType &= ~TRANSLATE; + + T.mMatrix[2][0] = -x; + T.mMatrix[2][1] = -y; + T.mType = TRANSLATE; + result = R * T; + } + return result; +} + uint32_t Transform::getType() const { return type() & 0xFF; } diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h index 4fe261af72..c4efade765 100644 --- a/services/surfaceflinger/Transform.h +++ b/services/surfaceflinger/Transform.h @@ -80,6 +80,8 @@ public: Rect transform(const Rect& bounds) const; Transform operator * (const Transform& rhs) const; + Transform inverse() const; + // for debugging void dump(const char* name) const; |