diff options
-rw-r--r-- | cmds/dumpstate/dumpstate.c | 2 | ||||
-rw-r--r-- | cmds/installd/commands.c | 2 | ||||
-rw-r--r-- | cmds/installd/installd.c | 2 | ||||
-rw-r--r-- | include/gui/SurfaceControl.h | 2 | ||||
-rw-r--r-- | libs/gui/Surface.cpp | 2 | ||||
-rw-r--r-- | libs/gui/SurfaceControl.cpp | 2 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayDevice.cpp | 131 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayDevice.h | 12 | ||||
-rw-r--r-- | services/surfaceflinger/Layer.cpp | 47 | ||||
-rw-r--r-- | services/surfaceflinger/Layer.h | 4 | ||||
-rw-r--r-- | services/surfaceflinger/LayerBase.cpp | 119 | ||||
-rw-r--r-- | services/surfaceflinger/LayerBase.h | 15 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 12 | ||||
-rw-r--r-- | services/surfaceflinger/Transform.cpp | 38 | ||||
-rw-r--r-- | services/surfaceflinger/Transform.h | 2 |
15 files changed, 262 insertions, 130 deletions
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index 1b8f755..9a1839d 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -25,7 +25,7 @@ #include <sys/time.h> #include <sys/wait.h> #include <unistd.h> -#include <linux/capability.h> +#include <sys/capability.h> #include <linux/prctl.h> #include <cutils/properties.h> diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c index c272e47..a58eca8 100644 --- a/cmds/installd/commands.c +++ b/cmds/installd/commands.c @@ -14,7 +14,7 @@ ** limitations under the License. */ -#include <linux/capability.h> +#include <sys/capability.h> #include "installd.h" #include <diskusage/dirsize.h> #include <selinux/android.h> diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c index 2285e79..f81dfe5 100644 --- a/cmds/installd/installd.c +++ b/cmds/installd/installd.c @@ -14,7 +14,7 @@ ** limitations under the License. */ -#include <linux/capability.h> +#include <sys/capability.h> #include <linux/prctl.h> #include "installd.h" diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h index 9268e7d..f70888d 100644 --- a/include/gui/SurfaceControl.h +++ b/include/gui/SurfaceControl.h @@ -57,7 +57,7 @@ public: status_t setLayerStack(int32_t layerStack); status_t setLayer(int32_t layer); - status_t setPosition(float x, float y); + status_t setPosition(int32_t x, int32_t y); status_t setSize(uint32_t w, uint32_t h); status_t hide(); status_t show(); diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 410ad5d..950d16a 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -735,7 +735,7 @@ status_t Surface::writeToParcel( sp<Surface> Surface::readFromParcel(const Parcel& data) { sp<IBinder> binder(data.readStrongBinder()); sp<IGraphicBufferProducer> bp(interface_cast<IGraphicBufferProducer>(binder)); - return new Surface(bp); + return bp != NULL ? new Surface(bp): NULL; } // ---------------------------------------------------------------------------- diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index e621b22..ef52269 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -106,7 +106,7 @@ status_t SurfaceControl::setLayer(int32_t layer) { const sp<SurfaceComposerClient>& client(mClient); return client->setLayer(mSurface, layer); } -status_t SurfaceControl::setPosition(float x, float y) { +status_t SurfaceControl::setPosition(int32_t x, int32_t y) { status_t err = validate(); if (err < 0) return err; const sp<SurfaceComposerClient>& client(mClient); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 9466944..ed2768c 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -89,7 +89,7 @@ DisplayDevice::DisplayDevice( mIsSecure(isSecure), mSecureLayerVisible(false), mScreenAcquired(false), - mLayerStack(0), + mLayerStack(NO_LAYER_STACK), mOrientation() { init(config); @@ -196,13 +196,13 @@ void DisplayDevice::flip(const Region& dirty) const EGLDisplay dpy = mDisplay; EGLSurface surface = mSurface; -#ifdef EGL_ANDROID_swap_rectangle +#ifdef EGL_ANDROID_swap_rectangle if (mFlags & SWAP_RECTANGLE) { const Region newDirty(dirty.intersect(bounds())); const Rect b(newDirty.getBounds()); eglSetSwapRectangleANDROID(dpy, surface, b.left, b.top, b.width(), b.height()); - } + } #endif mPageFlipCount++; @@ -287,7 +287,8 @@ void DisplayDevice::setVisibleLayersSortedByZ(const Vector< sp<LayerBase> >& lay mSecureLayerVisible = false; size_t count = layers.size(); for (size_t i=0 ; i<count ; i++) { - if (layers[i]->isSecure()) { + const sp<LayerBase>& layer(layers[i]); + if (layer->isSecure()) { mSecureLayerVisible = true; } } @@ -365,74 +366,72 @@ status_t DisplayDevice::orientationToTransfrom( } void DisplayDevice::setProjection(int orientation, - const Rect& viewport, const Rect& frame) { - mOrientation = orientation; - mViewport = viewport; - mFrame = frame; - updateGeometryTransform(); -} + const Rect& newViewport, const Rect& newFrame) { + Rect viewport(newViewport); + Rect frame(newFrame); -void DisplayDevice::updateGeometryTransform() { - int w = mDisplayWidth; - int h = mDisplayHeight; - Transform TL, TP, R, S; - if (DisplayDevice::orientationToTransfrom( - mOrientation, w, h, &R) == NO_ERROR) { - dirtyRegion.set(bounds()); - - Rect viewport(mViewport); - Rect frame(mFrame); - - if (!frame.isValid()) { - // the destination frame can be invalid if it has never been set, - // in that case we assume the whole display frame. - frame = Rect(w, h); - } + const int w = mDisplayWidth; + const int h = mDisplayHeight; - if (viewport.isEmpty()) { - // viewport can be invalid if it has never been set, in that case - // we assume the whole display size. - // it's also invalid to have an empty viewport, so we handle that - // case in the same way. - viewport = Rect(w, h); - if (R.getOrientation() & Transform::ROT_90) { - // viewport is always specified in the logical orientation - // of the display (ie: post-rotation). - swap(viewport.right, viewport.bottom); - } - } + Transform R; + DisplayDevice::orientationToTransfrom(orientation, w, h, &R); - float src_width = viewport.width(); - float src_height = viewport.height(); - float dst_width = frame.width(); - float dst_height = frame.height(); - if (src_width != dst_width || src_height != dst_height) { - float sx = dst_width / src_width; - float sy = dst_height / src_height; - S.set(sx, 0, 0, sy); - } + if (!frame.isValid()) { + // the destination frame can be invalid if it has never been set, + // in that case we assume the whole display frame. + frame = Rect(w, h); + } - float src_x = viewport.left; - float src_y = viewport.top; - float dst_x = frame.left; - float dst_y = frame.top; - TL.set(-src_x, -src_y); - TP.set(dst_x, dst_y); - - // The viewport and frame are both in the logical orientation. - // Apply the logical translation, scale to physical size, apply the - // physical translation and finally rotate to the physical orientation. - mGlobalTransform = R * TP * S * TL; - - const uint8_t type = mGlobalTransform.getType(); - mNeedsFiltering = (!mGlobalTransform.preserveRects() || - (type >= Transform::SCALE)); - - mScissor = mGlobalTransform.transform(mViewport); - if (mScissor.isEmpty()) { - mScissor.set(getBounds()); + if (viewport.isEmpty()) { + // viewport can be invalid if it has never been set, in that case + // we assume the whole display size. + // it's also invalid to have an empty viewport, so we handle that + // case in the same way. + viewport = Rect(w, h); + if (R.getOrientation() & Transform::ROT_90) { + // viewport is always specified in the logical orientation + // of the display (ie: post-rotation). + swap(viewport.right, viewport.bottom); } } + + dirtyRegion.set(getBounds()); + + Transform TL, TP, S; + float src_width = viewport.width(); + float src_height = viewport.height(); + float dst_width = frame.width(); + float dst_height = frame.height(); + if (src_width != dst_width || src_height != dst_height) { + float sx = dst_width / src_width; + float sy = dst_height / src_height; + S.set(sx, 0, 0, sy); + } + + float src_x = viewport.left; + float src_y = viewport.top; + float dst_x = frame.left; + float dst_y = frame.top; + TL.set(-src_x, -src_y); + TP.set(dst_x, dst_y); + + // The viewport and frame are both in the logical orientation. + // Apply the logical translation, scale to physical size, apply the + // physical translation and finally rotate to the physical orientation. + mGlobalTransform = R * TP * S * TL; + + const uint8_t type = mGlobalTransform.getType(); + mNeedsFiltering = (!mGlobalTransform.preserveRects() || + (type >= Transform::SCALE)); + + mScissor = mGlobalTransform.transform(viewport); + if (mScissor.isEmpty()) { + mScissor.set(getBounds()); + } + + mOrientation = orientation; + mViewport = viewport; + mFrame = frame; } void DisplayDevice::dump(String8& result, char* buffer, size_t SIZE) const { diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index bb6eb70..91f34db 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -65,6 +65,10 @@ public: SWAP_RECTANGLE = 0x00080000, }; + enum { + NO_LAYER_STACK = 0xFFFFFFFF, + }; + DisplayDevice( const sp<SurfaceFlinger>& flinger, DisplayType type, @@ -105,8 +109,8 @@ public: int getOrientation() const { return mOrientation; } const Transform& getTransform() const { return mGlobalTransform; } - const Rect& getViewport() const { return mViewport; } - const Rect& getFrame() const { return mFrame; } + const Rect getViewport() const { return mViewport; } + const Rect getFrame() const { return mFrame; } const Rect& getScissor() const { return mScissor; } bool needsFiltering() const { return mNeedsFiltering; } @@ -117,7 +121,7 @@ public: void swapBuffers(HWComposer& hwc) const; status_t compositionComplete() const; - + // called after h/w composer has completed its set() call void onSwapBuffersCompleted(HWComposer& hwc) const; @@ -197,8 +201,6 @@ private: static status_t orientationToTransfrom(int orientation, int w, int h, Transform* tr); - void updateGeometryTransform(); - uint32_t mLayerStack; int mOrientation; // user-provided visible area of the layer stack diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 439acb5..c9f1eb5 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -19,7 +19,6 @@ #include <stdlib.h> #include <stdint.h> #include <sys/types.h> -#include <math.h> #include <cutils/compiler.h> #include <cutils/native_handle.h> @@ -200,48 +199,27 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, return NO_ERROR; } -Rect Layer::computeBufferCrop() const { - // Start with the SurfaceFlingerConsumer's buffer crop... +Rect Layer::getContentCrop() const { + // this is the crop rectangle that applies to the buffer + // itself (as opposed to the window) Rect crop; if (!mCurrentCrop.isEmpty()) { + // if the buffer crop is defined, we use that crop = mCurrentCrop; - } else if (mActiveBuffer != NULL){ - crop = Rect(mActiveBuffer->getWidth(), mActiveBuffer->getHeight()); + } else if (mActiveBuffer != NULL) { + // otherwise we use the whole buffer + crop = mActiveBuffer->getBounds(); } else { + // if we don't have a buffer yet, we use an empty/invalid crop crop.makeInvalid(); - return crop; } - - // ... then reduce that in the same proportions as the window crop reduces - // the window size. - const State& s(drawingState()); - if (!s.active.crop.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; - int winWidth = s.active.w; - int winHeight = s.active.h; - if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { - invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | - NATIVE_WINDOW_TRANSFORM_FLIP_H; - winWidth = s.active.h; - winHeight = s.active.w; - } - Rect winCrop = s.active.crop.transform(invTransform, - s.active.w, s.active.h); - - float xScale = float(crop.width()) / float(winWidth); - float yScale = float(crop.height()) / float(winHeight); - crop.left += int(ceilf(float(winCrop.left) * xScale)); - crop.top += int(ceilf(float(winCrop.top) * yScale)); - crop.right -= int(ceilf(float(winWidth - winCrop.right) * xScale)); - crop.bottom -= int(ceilf(float(winHeight - winCrop.bottom) * yScale)); - } - return crop; } +uint32_t Layer::getContentTransform() const { + return mCurrentTransform; +} + void Layer::setGeometry( const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer) @@ -278,7 +256,6 @@ void Layer::setGeometry( } else { layer.setTransform(finalTransform); } - layer.setCrop(computeBufferCrop()); } void Layer::setPerFrameData(const sp<const DisplayDevice>& hw, diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 5fd7e59..e57fb59 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -103,6 +103,9 @@ public: // the current orientation of the display device. virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const; + virtual Rect getContentCrop() const; + virtual uint32_t getContentTransform() const; + protected: virtual void onFirstRef(); virtual void dump(String8& result, char* scratch, size_t size) const; @@ -119,7 +122,6 @@ private: uint32_t getEffectiveUsage(uint32_t usage) const; bool isCropped() const; - Rect computeBufferCrop() const; static bool getOpacityForFormat(uint32_t format); // Interface implementation for SurfaceFlingerConsumer::FrameAvailableListener diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp index dfdbf30..db2b20e 100644 --- a/services/surfaceflinger/LayerBase.cpp +++ b/services/surfaceflinger/LayerBase.cpp @@ -17,6 +17,7 @@ #include <stdlib.h> #include <stdint.h> #include <sys/types.h> +#include <math.h> #include <utils/Errors.h> #include <utils/Log.h> @@ -259,7 +260,7 @@ Rect LayerBase::computeBounds() const { if (!s.active.crop.isEmpty()) { win.intersect(s.active.crop, &win); } - return s.transform.transform(win); + return win; } Region LayerBase::latchBuffer(bool& recomputeVisibleRegions) { @@ -267,6 +268,83 @@ Region LayerBase::latchBuffer(bool& recomputeVisibleRegions) { return result; } + +Rect LayerBase::getContentCrop() const { + // regular layers just use their active area as the content crop + const State& s(drawingState()); + return Rect(s.active.w, s.active.h); +} + +uint32_t LayerBase::getContentTransform() const { + // regular layers don't have a content transform + return 0; +} + +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()); + + // the active.crop is the area of the window that gets cropped, but not + // scaled in any ways. + const State& s(drawingState()); + + // 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 + // SurfaceFlingerConsumer. + uint32_t invTransform = getContentTransform(); + int winWidth = s.active.w; + int winHeight = s.active.h; + if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { + 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); + + // the code below essentially performs a scaled intersection + // of crop and winCrop + float xScale = float(crop.width()) / float(winWidth); + float yScale = float(crop.height()) / float(winHeight); + + int insetL = int(ceilf( winCrop.left * xScale)); + int insetT = int(ceilf( winCrop.top * yScale)); + int insetR = int(ceilf((winWidth - winCrop.right ) * xScale)); + int insetB = int(ceilf((winHeight - winCrop.bottom) * yScale)); + + crop.left += insetL; + crop.top += insetT; + crop.right -= insetR; + crop.bottom -= insetB; + } + return crop; +} + void LayerBase::setGeometry( const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer) @@ -289,13 +367,15 @@ void LayerBase::setGeometry( HWC_BLENDING_COVERAGE); } - const Transform& tr = hw->getTransform(); - Rect transformedBounds(computeBounds()); - transformedBounds = tr.transform(transformedBounds); - // scaling is already applied in transformedBounds - layer.setFrame(transformedBounds); - layer.setCrop(transformedBounds.getBounds()); + // apply the layer's transform, followed by the display's global transform + // 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)); } void LayerBase::setPerFrameData(const sp<const DisplayDevice>& hw, @@ -303,8 +383,11 @@ void LayerBase::setPerFrameData(const sp<const DisplayDevice>& hw, // we have to set the visible region on every frame because // we currently free it during onLayerDisplayed(), which is called // after HWComposer::commit() -- every frame. + // Apply this display's projection's viewport to the visible region + // before giving it to the HWC HAL. const Transform& tr = hw->getTransform(); - layer.setVisibleRegionScreen(tr.transform(visibleRegion)); + Region visible = tr.transform(visibleRegion.intersect(hw->getViewport())); + layer.setVisibleRegionScreen(visible); } void LayerBase::setAcquireFence(const sp<const DisplayDevice>& hw, @@ -404,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/LayerBase.h b/services/surfaceflinger/LayerBase.h index c2624df..ecae2d9 100644 --- a/services/surfaceflinger/LayerBase.h +++ b/services/surfaceflinger/LayerBase.h @@ -260,6 +260,18 @@ public: */ virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const { } + /** + * returns the rectangle that crops the content of the layer and scales it + * to the layer's size. + */ + virtual Rect getContentCrop() const; + + /* + * returns the transform bits (90 rotation / h-flip / v-flip) of the + * layer's content + */ + virtual uint32_t getContentTransform() const; + /** always call base class first */ virtual void dump(String8& result, char* scratch, size_t size) const; virtual void shortDump(String8& result, char* scratch, size_t size) const; @@ -282,6 +294,9 @@ public: void setFiltering(bool filtering); bool getFiltering() const; +private: + Rect computeCrop(const sp<const DisplayDevice>& hw) const; + protected: void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip, GLclampf r, GLclampf g, GLclampf b, GLclampf alpha) const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 0971faa..8fa0800 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1347,7 +1347,7 @@ void SurfaceFlinger::computeVisibleRegions( // start with the whole surface at its current location const Layer::State& s(layer->drawingState()); - // only consider the layers on the given later stack + // only consider the layers on the given layer stack if (s.layerStack != layerStack) continue; @@ -1384,7 +1384,7 @@ void SurfaceFlinger::computeVisibleRegions( // handle hidden surfaces by setting the visible region to empty if (CC_LIKELY(layer->isVisible())) { const bool translucent = !layer->isOpaque(); - Rect bounds(layer->computeBounds()); + Rect bounds(s.transform.transform(layer->computeBounds())); visibleRegion.set(bounds); if (!visibleRegion.isEmpty()) { // Remove the transparent area from the visible region @@ -2073,12 +2073,14 @@ status_t SurfaceFlinger::onLayerDestroyed(const wp<LayerBaseClient>& layer) // --------------------------------------------------------------------------- void SurfaceFlinger::onInitializeDisplays() { - // reset screen orientation + // reset screen orientation and use primary layer stack Vector<ComposerState> state; Vector<DisplayState> displays; DisplayState d; - d.what = DisplayState::eDisplayProjectionChanged; + d.what = DisplayState::eDisplayProjectionChanged | + DisplayState::eLayerStackChanged; d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]; + d.layerStack = 0; d.orientation = DisplayState::eOrientationDefault; d.frame.makeInvalid(); d.viewport.makeInvalid(); @@ -2922,7 +2924,7 @@ SurfaceFlinger::DisplayDeviceState::DisplayDeviceState() } SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type) - : type(type), layerStack(0), orientation(0) { + : type(type), layerStack(DisplayDevice::NO_LAYER_STACK), orientation(0) { viewport.makeInvalid(); frame.makeInvalid(); } diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp index aca90e0..315720e 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 4fe261a..c4efade 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; |