Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3da1672a authored by Mathias Agopian's avatar Mathias Agopian
Browse files

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
parent a8bca8d8
Loading
Loading
Loading
Loading
+40 −5
Original line number Diff line number Diff line
@@ -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);
+38 −0
Original line number Diff line number Diff line
@@ -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;
}
+2 −0
Original line number Diff line number Diff line
@@ -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;