diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h index f3c0ecbc8..7320e4d1f 100644 --- a/include/gui/ISurfaceComposer.h +++ b/include/gui/ISurfaceComposer.h @@ -67,6 +67,7 @@ public: eTransparentRegionChanged = 0x00000020, eVisibilityChanged = 0x00000040, eFreezeTintChanged = 0x00000080, + eCropChanged = 0x00000100, }; enum { diff --git a/include/gui/Surface.h b/include/gui/Surface.h index 1f90c595a..50bdf710f 100644 --- a/include/gui/Surface.h +++ b/include/gui/Surface.h @@ -72,6 +72,7 @@ public: status_t setAlpha(float alpha=1.0f); status_t setMatrix(float dsdx, float dtdx, float dsdy, float dtdy); status_t setFreezeTint(uint32_t tint); + status_t setCrop(const Rect& crop); static status_t writeSurfaceToParcel( const sp& control, Parcel* parcel); diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h index d971031c0..3bd10de91 100644 --- a/include/gui/SurfaceComposerClient.h +++ b/include/gui/SurfaceComposerClient.h @@ -127,6 +127,7 @@ public: status_t setMatrix(SurfaceID id, float dsdx, float dtdx, float dsdy, float dtdy); status_t setPosition(SurfaceID id, float x, float y); status_t setSize(SurfaceID id, uint32_t w, uint32_t h); + status_t setCrop(SurfaceID id, const Rect& crop); status_t destroySurface(SurfaceID sid); private: diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h index ca277e02b..9151c1192 100644 --- a/include/private/gui/LayerState.h +++ b/include/private/gui/LayerState.h @@ -23,6 +23,7 @@ #include #include +#include #include namespace android { @@ -40,6 +41,7 @@ struct layer_state_t { { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; + crop.makeInvalid(); } status_t write(Parcel& output) const; @@ -64,6 +66,7 @@ struct layer_state_t { uint8_t mask; uint8_t reserved; matrix22_t matrix; + Rect crop; // non POD must be last. see write/read Region transparentRegion; }; diff --git a/include/ui/Rect.h b/include/ui/Rect.h index bd820618f..308da7b67 100644 --- a/include/ui/Rect.h +++ b/include/ui/Rect.h @@ -147,7 +147,7 @@ public: // a ROT90 then the output rectangle is defined in a space extending to // (height, width). Otherwise the output rectangle is in the same space as // the input. - Rect transform(uint32_t xform, int32_t width, int32_t height); + Rect transform(uint32_t xform, int32_t width, int32_t height) const; }; ANDROID_BASIC_TYPES_TRAITS(Rect) diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 059f3136d..d7590f013 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -164,6 +164,12 @@ status_t SurfaceControl::setFreezeTint(uint32_t tint) { const sp& client(mClient); return client->setFreezeTint(mToken, tint); } +status_t SurfaceControl::setCrop(const Rect& crop) { + status_t err = validate(); + if (err < 0) return err; + const sp& client(mClient); + return client->setCrop(mToken, crop); +} status_t SurfaceControl::validate() const { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index ceb1ba6d8..8fa21671e 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -125,6 +125,8 @@ public: const sp& client, SurfaceID id, uint32_t tint); status_t setOrientation(int orientation); + status_t setCrop(const sp& client, SurfaceID id, + const Rect& crop); static void closeGlobalTransaction(bool synchronous) { Composer::getInstance().closeGlobalTransactionImpl(synchronous); @@ -290,6 +292,17 @@ status_t Composer::setOrientation(int orientation) { return NO_ERROR; } +status_t Composer::setCrop(const sp& client, + SurfaceID id, const Rect& crop) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= ISurfaceComposer::eCropChanged; + s->crop = crop; + return NO_ERROR; +} + // --------------------------------------------------------------------------- SurfaceComposerClient::SurfaceComposerClient() @@ -398,6 +411,10 @@ void SurfaceComposerClient::closeGlobalTransaction(bool synchronous) { // ---------------------------------------------------------------------------- +status_t SurfaceComposerClient::setCrop(SurfaceID id, const Rect& crop) { + return getComposer().setCrop(this, id, crop); +} + status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint) { return getComposer().setFreezeTint(this, id, tint); } diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp index 65fe5f9da..c4dd55ba3 100644 --- a/libs/ui/Rect.cpp +++ b/libs/ui/Rect.cpp @@ -93,7 +93,7 @@ bool Rect::intersect(const Rect& with, Rect* result) const return !(result->isEmpty()); } -Rect Rect::transform(uint32_t xform, int32_t width, int32_t height) { +Rect Rect::transform(uint32_t xform, int32_t width, int32_t height) const { Rect result(*this); if (xform & HAL_TRANSFORM_FLIP_H) { result = Rect(width - result.right, result.top, diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 6bc80eea9..2899db742 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -141,47 +141,6 @@ void Layer::setName(const String8& name) { void Layer::validateVisibility(const Transform& globalTransform) { LayerBase::validateVisibility(globalTransform); - if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_FREEZE && - !mCurrentCrop.isEmpty()) { - // We need to shrink the window size to match the buffer crop - // rectangle. - const Layer::State& s(drawingState()); - const Transform tr(globalTransform * s.transform); - float windowWidth = s.w; - float windowHeight = s.h; - float bufferWidth = mActiveBuffer->getWidth(); - float bufferHeight = mActiveBuffer->getHeight(); - if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { - float tmp = bufferWidth; - bufferWidth = bufferHeight; - bufferHeight = tmp; - } - float xScale = float(windowWidth) / float(bufferWidth); - float yScale = float(windowHeight) / float(bufferHeight); - - // Compute the crop in post-transform coordinates. - Rect crop(mCurrentCrop.transform(mCurrentTransform, - mActiveBuffer->getWidth(), mActiveBuffer->getHeight())); - - float left = ceil(xScale * float(crop.left)); - float right = floor(xScale * float(crop.right)); - float top = ceil(yScale * float(crop.top)); - float bottom = floor(yScale * float(crop.bottom)); - - tr.transform(mVertices[0], left, top); - tr.transform(mVertices[1], left, bottom); - tr.transform(mVertices[2], right, bottom); - tr.transform(mVertices[3], right, top); - - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const uint32_t hw_h = hw.getHeight(); - for (size_t i=0 ; i<4 ; i++) - mVertices[i][1] = hw_h - mVertices[i][1]; - - mTransformedBounds = tr.transform( - Rect(int(left), int(top), int(right), int(bottom))); - } - // This optimization allows the SurfaceTexture to bake in // the rotation so hardware overlays can be used mSurfaceTexture->setTransformHint(getTransformHint()); @@ -259,6 +218,46 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, return NO_ERROR; } +Rect Layer::computeBufferCrop() const { + // Start with the SurfaceTexture's buffer crop... + Rect crop; + if (!mCurrentCrop.isEmpty()) { + crop = mCurrentCrop; + } else if (mActiveBuffer != NULL){ + crop = Rect(mActiveBuffer->getWidth(), mActiveBuffer->getHeight()); + } else { + crop = Rect(mTransformedBounds.width(), mTransformedBounds.height()); + } + + // ... then reduce that in the same proportions as the window crop reduces + // the window size. + const State& s(drawingState()); + if (!s.crop.isEmpty()) { + // Transform the window crop to match the buffer coordinate system, + // which means using the inverse of the current transform set on the + // SurfaceTexture. + uint32_t invTransform = mCurrentTransform; + int winWidth = s.w; + int winHeight = s.h; + if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { + invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | + NATIVE_WINDOW_TRANSFORM_FLIP_H; + winWidth = s.h; + winHeight = s.w; + } + Rect winCrop = s.crop.transform(invTransform, s.w, s.h); + + float xScale = float(crop.width()) / float(winWidth); + float yScale = float(crop.height()) / float(winHeight); + crop.left += int(ceil(float(winCrop.left) * xScale)); + crop.top += int(ceil(float(winCrop.top) * yScale)); + crop.right -= int(ceil(float(winWidth - winCrop.right) * xScale)); + crop.bottom -= int(ceil(float(winHeight - winCrop.bottom) * yScale)); + } + + return crop; +} + void Layer::setGeometry(hwc_layer_t* hwcl) { LayerBaseClient::setGeometry(hwcl); @@ -293,23 +292,11 @@ void Layer::setGeometry(hwc_layer_t* hwcl) hwcl->transform = finalTransform; } - if (isCropped()) { - hwcl->sourceCrop.left = mCurrentCrop.left; - hwcl->sourceCrop.top = mCurrentCrop.top; - hwcl->sourceCrop.right = mCurrentCrop.right; - hwcl->sourceCrop.bottom = mCurrentCrop.bottom; - } else { - const sp& buffer(mActiveBuffer); - hwcl->sourceCrop.left = 0; - hwcl->sourceCrop.top = 0; - if (buffer != NULL) { - hwcl->sourceCrop.right = buffer->width; - hwcl->sourceCrop.bottom = buffer->height; - } else { - hwcl->sourceCrop.right = mTransformedBounds.width(); - hwcl->sourceCrop.bottom = mTransformedBounds.height(); - } - } + Rect crop = computeBufferCrop(); + hwcl->sourceCrop.left = crop.left; + hwcl->sourceCrop.top = crop.top; + hwcl->sourceCrop.right = crop.right; + hwcl->sourceCrop.bottom = crop.bottom; } void Layer::setPerFrameData(hwc_layer_t* hwcl) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 1188621b8..393599f3a 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -101,6 +101,7 @@ private: uint32_t getEffectiveUsage(uint32_t usage) const; uint32_t getTransformHint() const; bool isCropped() const; + Rect computeBufferCrop() const; static bool getOpacityForFormat(uint32_t format); // ----------------------------------------------------------------------- diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp index 694ecdef3..81031b14f 100644 --- a/services/surfaceflinger/LayerBase.cpp +++ b/services/surfaceflinger/LayerBase.cpp @@ -93,6 +93,7 @@ void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags) mCurrentState.flags = layerFlags; mCurrentState.sequence = 0; mCurrentState.transform.set(0, 0); + mCurrentState.crop.makeInvalid(); // drawing state & current state are identical mDrawingState = mCurrentState; @@ -172,6 +173,14 @@ bool LayerBase::setFlags(uint8_t flags, uint8_t mask) { requestTransaction(); return true; } +bool LayerBase::setCrop(const Rect& crop) { + if (mCurrentState.crop == crop) + return false; + mCurrentState.sequence++; + mCurrentState.crop = crop; + requestTransaction(); + return true; +} Rect LayerBase::visibleBounds() const { @@ -229,15 +238,18 @@ void LayerBase::validateVisibility(const Transform& planeTransform) const bool transformed = tr.transformed(); const DisplayHardware& hw(graphicPlane(0).displayHardware()); const uint32_t hw_h = hw.getHeight(); + const Rect& crop(s.crop); - uint32_t w = s.w; - uint32_t h = s.h; + Rect win(s.w, s.h); + if (!crop.isEmpty()) { + win.intersect(crop, &win); + } mNumVertices = 4; - tr.transform(mVertices[0], 0, 0); - tr.transform(mVertices[1], 0, h); - tr.transform(mVertices[2], w, h); - tr.transform(mVertices[3], w, 0); + tr.transform(mVertices[0], win.left, win.top); + tr.transform(mVertices[1], win.left, win.bottom); + tr.transform(mVertices[2], win.right, win.bottom); + tr.transform(mVertices[3], win.right, win.top); for (size_t i=0 ; i<4 ; i++) mVertices[i][1] = hw_h - mVertices[i][1]; @@ -260,7 +272,7 @@ void LayerBase::validateVisibility(const Transform& planeTransform) mOrientation = tr.getOrientation(); mPlaneOrientation = planeTransform.getOrientation(); mTransform = tr; - mTransformedBounds = tr.makeBounds(w, h); + mTransformedBounds = tr.transform(win); } void LayerBase::lockPageFlip(bool& recomputeVisibleRegions) { @@ -391,15 +403,27 @@ void LayerBase::drawWithOpenGL(const Region& clip) const GLfloat v; }; + Rect crop(s.w, s.h); + if (!s.crop.isEmpty()) { + crop = s.crop; + } + GLfloat left = GLfloat(crop.left) / GLfloat(s.w); + GLfloat top = GLfloat(crop.top) / GLfloat(s.h); + GLfloat right = GLfloat(crop.right) / GLfloat(s.w); + GLfloat bottom = GLfloat(crop.bottom) / GLfloat(s.h); + TexCoords texCoords[4]; - texCoords[0].u = 0; - texCoords[0].v = 1; - texCoords[1].u = 0; - texCoords[1].v = 0; - texCoords[2].u = 1; - texCoords[2].v = 0; - texCoords[3].u = 1; - texCoords[3].v = 1; + texCoords[0].u = left; + texCoords[0].v = top; + texCoords[1].u = left; + texCoords[1].v = bottom; + texCoords[2].u = right; + texCoords[2].v = bottom; + texCoords[3].u = right; + texCoords[3].v = top; + for (int i = 0; i < 4; i++) { + texCoords[i].v = 1.0f - texCoords[i].v; + } glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(2, GL_FLOAT, 0, mVertices); diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h index d123d9bc9..31f6dfdc6 100644 --- a/services/surfaceflinger/LayerBase.h +++ b/services/surfaceflinger/LayerBase.h @@ -78,6 +78,7 @@ public: uint32_t tint; Transform transform; Region transparentRegion; + Rect crop; }; virtual void setName(const String8& name); @@ -91,6 +92,7 @@ public: bool setMatrix(const layer_state_t::matrix22_t& matrix); bool setTransparentRegionHint(const Region& opaque); bool setFlags(uint8_t flags, uint8_t mask); + bool setCrop(const Rect& crop); void commitTransaction(); bool requestTransaction(); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 0d4d2b97a..35a7fd51b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1352,6 +1352,10 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (layer->setFlags(s.flags, s.mask)) flags |= eTraversalNeeded; } + if (what & eCropChanged) { + if (layer->setCrop(s.crop)) + flags |= eTraversalNeeded; + } } return flags; }