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

Commit 1eae0ee4 authored by Mathias Agopian's avatar Mathias Agopian
Browse files

clean-up SurfaceFlinger a bit

- most methods on Layer didn't need to be virtual
- more consistency in naming drawing/current state

Change-Id: Ieb7b4951b40fc673b807994ed21ae4aea7281068
parent 2e3a7f1e
Loading
Loading
Loading
Loading
+53 −53
Original line number Diff line number Diff line
@@ -165,7 +165,7 @@ void Layer::onRemoved() {
// set-up
// ---------------------------------------------------------------------------

String8 Layer::getName() const {
const String8& Layer::getName() const {
    return mName;
}

@@ -281,7 +281,7 @@ static Rect reduce(const Rect& win, const Region& exclude) {
}

Rect Layer::computeBounds() const {
    const Layer::State& s(drawingState());
    const Layer::State& s(getDrawingState());
    Rect win(s.active.w, s.active.h);
    if (!s.active.crop.isEmpty()) {
        win.intersect(s.active.crop, &win);
@@ -305,7 +305,7 @@ Rect Layer::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());
    const State& s(getDrawingState());

    // apply the projection's clipping to the window crop in
    // layerstack space, and convert-back to layer space.
@@ -372,7 +372,7 @@ void Layer::setGeometry(
    }

    // this gives us only the "orientation" component of the transform
    const State& s(drawingState());
    const State& s(getDrawingState());
    if (!isOpaque() || s.alpha != 0xFF) {
        layer.setBlending(mPremultipliedAlpha ?
                HWC_BLENDING_PREMULT :
@@ -627,7 +627,7 @@ static void setupOpenGL11(bool premultipliedAlpha, bool opaque, int alpha) {
void Layer::drawWithOpenGL(
        const sp<const DisplayDevice>& hw, const Region& clip) const {
    const uint32_t fbHeight = hw->getHeight();
    const State& s(drawingState());
    const State& s(getDrawingState());

    if (mFlinger->getGlesVersion() == GLES_VERSION_1_0) {
        setupOpenGL10(mPremultipliedAlpha, isOpaque(), s.alpha);
@@ -730,7 +730,7 @@ bool Layer::getOpacityForFormat(uint32_t format)

void Layer::computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const
{
    const Layer::State& s(drawingState());
    const Layer::State& s(getDrawingState());
    const Transform tr(hw->getTransform() * s.transform);
    const uint32_t hw_h = hw->getHeight();
    Rect win(s.active.w, s.active.h);
@@ -805,11 +805,11 @@ void Layer::setVisibleNonTransparentRegion(const Region&
uint32_t Layer::doTransaction(uint32_t flags) {
    ATRACE_CALL();

    const Layer::State& front(drawingState());
    const Layer::State& temp(currentState());
    const Layer::State& s(getDrawingState());
    const Layer::State& c(getCurrentState());

    const bool sizeChanged = (temp.requested.w != front.requested.w) ||
                             (temp.requested.h != front.requested.h);
    const bool sizeChanged = (c.requested.w != s.requested.w) ||
                             (c.requested.h != s.requested.h);

    if (sizeChanged) {
        // the size changed, we need to ask our client to request a new buffer
@@ -819,46 +819,46 @@ uint32_t Layer::doTransaction(uint32_t flags) {
                "            requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n"
                "  drawing={ active   ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
                "            requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n",
                this, (const char*) getName(), mCurrentTransform, mCurrentScalingMode,
                temp.active.w, temp.active.h,
                temp.active.crop.left,
                temp.active.crop.top,
                temp.active.crop.right,
                temp.active.crop.bottom,
                temp.active.crop.getWidth(),
                temp.active.crop.getHeight(),
                temp.requested.w, temp.requested.h,
                temp.requested.crop.left,
                temp.requested.crop.top,
                temp.requested.crop.right,
                temp.requested.crop.bottom,
                temp.requested.crop.getWidth(),
                temp.requested.crop.getHeight(),
                front.active.w, front.active.h,
                front.active.crop.left,
                front.active.crop.top,
                front.active.crop.right,
                front.active.crop.bottom,
                front.active.crop.getWidth(),
                front.active.crop.getHeight(),
                front.requested.w, front.requested.h,
                front.requested.crop.left,
                front.requested.crop.top,
                front.requested.crop.right,
                front.requested.crop.bottom,
                front.requested.crop.getWidth(),
                front.requested.crop.getHeight());
                this, getName().string(), mCurrentTransform, mCurrentScalingMode,
                c.active.w, c.active.h,
                c.active.crop.left,
                c.active.crop.top,
                c.active.crop.right,
                c.active.crop.bottom,
                c.active.crop.getWidth(),
                c.active.crop.getHeight(),
                c.requested.w, c.requested.h,
                c.requested.crop.left,
                c.requested.crop.top,
                c.requested.crop.right,
                c.requested.crop.bottom,
                c.requested.crop.getWidth(),
                c.requested.crop.getHeight(),
                s.active.w, s.active.h,
                s.active.crop.left,
                s.active.crop.top,
                s.active.crop.right,
                s.active.crop.bottom,
                s.active.crop.getWidth(),
                s.active.crop.getHeight(),
                s.requested.w, s.requested.h,
                s.requested.crop.left,
                s.requested.crop.top,
                s.requested.crop.right,
                s.requested.crop.bottom,
                s.requested.crop.getWidth(),
                s.requested.crop.getHeight());

        // record the new size, form this point on, when the client request
        // a buffer, it'll get the new size.
        mSurfaceFlingerConsumer->setDefaultBufferSize(
                temp.requested.w, temp.requested.h);
                c.requested.w, c.requested.h);
    }

    if (!isFixedSize()) {

        const bool resizePending = (temp.requested.w != temp.active.w) ||
                                   (temp.requested.h != temp.active.h);
        const bool resizePending = (c.requested.w != c.active.w) ||
                                   (c.requested.h != c.active.h);

        if (resizePending) {
            // don't let Layer::doTransaction update the drawing state
@@ -878,23 +878,23 @@ uint32_t Layer::doTransaction(uint32_t flags) {
    // this is used by Layer, which special cases resizes.
    if (flags & eDontUpdateGeometryState)  {
    } else {
        Layer::State& editTemp(currentState());
        editTemp.active = temp.requested;
        Layer::State& editCurrentState(getCurrentState());
        editCurrentState.active = c.requested;
    }

    if (front.active != temp.active) {
    if (s.active != c.active) {
        // invalidate and recompute the visible regions if needed
        flags |= Layer::eVisibleRegion;
    }

    if (temp.sequence != front.sequence) {
    if (c.sequence != s.sequence) {
        // invalidate and recompute the visible regions if needed
        flags |= eVisibleRegion;
        this->contentDirty = true;

        // we may use linear filtering, if the matrix scales us
        const uint8_t type = temp.transform.getType();
        mNeedsFiltering = (!temp.transform.preserveRects() ||
        const uint8_t type = c.transform.getType();
        mNeedsFiltering = (!c.transform.preserveRects() ||
                (type >= Transform::SCALE));
    }

@@ -1159,7 +1159,7 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
        };


        Reject r(mDrawingState, currentState(), recomputeVisibleRegions);
        Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions);

        if (mSurfaceFlingerConsumer->updateTexImage(&r) != NO_ERROR) {
            // something happened!
@@ -1213,11 +1213,11 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
        glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        // FIXME: postedRegion should be dirty & bounds
        const Layer::State& front(drawingState());
        Region dirtyRegion(Rect(front.active.w, front.active.h));
        const Layer::State& s(getDrawingState());
        Region dirtyRegion(Rect(s.active.w, s.active.h));

        // transform the dirty region to window-manager space
        outDirtyRegion = (front.transform.transform(dirtyRegion));
        outDirtyRegion = (s.transform.transform(dirtyRegion));
    }
    return outDirtyRegion;
}
@@ -1254,7 +1254,7 @@ void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const {

void Layer::dump(String8& result, Colorizer& colorizer) const
{
    const Layer::State& s(drawingState());
    const Layer::State& s(getDrawingState());

    colorizer.colorize(result, Colorizer::GREEN);
    result.appendFormat(
+66 −65
Original line number Diff line number Diff line
@@ -131,6 +131,7 @@ public:

    Layer(SurfaceFlinger* flinger, const sp<Client>& client,
            const String8& name, uint32_t w, uint32_t h, uint32_t flags);

    virtual ~Layer();

    // the this layer's size and format
@@ -147,8 +148,6 @@ public:
    bool setCrop(const Rect& crop);
    bool setLayerStack(uint32_t layerStack);

    void commitTransaction();

    uint32_t getTransactionFlags(uint32_t flags);
    uint32_t setTransactionFlags(uint32_t flags);

@@ -157,79 +156,104 @@ public:

    sp<IBinder> getHandle();
    sp<BufferQueue> getBufferQueue() const;
    String8 getName() const;
    const String8& getName() const;

    // -----------------------------------------------------------------------
    // Virtuals

    virtual const char* getTypeId() const { return "Layer"; }

    virtual void setGeometry(const sp<const DisplayDevice>& hw,
    /*
     * isOpaque - true if this surface is opaque
     */
    virtual bool isOpaque() const;

    /*
     * isSecure - true if this surface is secure, that is if it prevents
     * screenshots or VNC servers.
     */
    virtual bool isSecure() const           { return mSecure; }

    /*
     * isProtected - true if the layer may contain protected content in the
     * GRALLOC_USAGE_PROTECTED sense.
     */
    virtual bool isProtected() const;

    /*
     * isVisible - true if this layer is visible, false otherwise
     */
    virtual bool isVisible() const;

    /*
     * isFixedSize - true if content has a fixed size
     */
    virtual bool isFixedSize() const;

protected:
    /*
     * onDraw - draws the surface.
     */
    virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const;

public:
    // -----------------------------------------------------------------------

    void setGeometry(const sp<const DisplayDevice>& hw,
            HWComposer::HWCLayerInterface& layer);
    virtual void setPerFrameData(const sp<const DisplayDevice>& hw,
    void setPerFrameData(const sp<const DisplayDevice>& hw,
            HWComposer::HWCLayerInterface& layer);
    virtual void setAcquireFence(const sp<const DisplayDevice>& hw,
    void setAcquireFence(const sp<const DisplayDevice>& hw,
            HWComposer::HWCLayerInterface& layer);

    /*
     * called after page-flip
     */
    virtual void onLayerDisplayed(const sp<const DisplayDevice>& hw,
    void onLayerDisplayed(const sp<const DisplayDevice>& hw,
            HWComposer::HWCLayerInterface* layer);

    /*
     * called before composition.
     * returns true if the layer has pending updates.
     */
    virtual bool onPreComposition();
    bool onPreComposition();

    /*
     *  called after composition.
     */
    virtual void onPostComposition();
    void onPostComposition();

    /*
     * draw - performs some global clipping optimizations
     * and calls onDraw().
     * Typically this method is not overridden, instead implement onDraw()
     * to perform the actual drawing.
     */
    virtual void draw(const sp<const DisplayDevice>& hw, const Region& clip) const;
    virtual void draw(const sp<const DisplayDevice>& hw);

    /*
     * onDraw - draws the surface.
     */
    virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const;

    /*
     * needsLinearFiltering - true if this surface's state requires filtering
     */
    virtual bool needsFiltering(const sp<const DisplayDevice>& hw) const;
    void draw(const sp<const DisplayDevice>& hw, const Region& clip) const;
    void draw(const sp<const DisplayDevice>& hw);

    /*
     * doTransaction - process the transaction. This is a good place to figure
     * out which attributes of the surface have changed.
     */
    virtual uint32_t doTransaction(uint32_t transactionFlags);
    uint32_t doTransaction(uint32_t transactionFlags);

    /*
     * setVisibleRegion - called to set the new visible region. This gives
     * a chance to update the new visible region or record the fact it changed.
     */
    virtual void setVisibleRegion(const Region& visibleRegion);
    void setVisibleRegion(const Region& visibleRegion);

    /*
     * setCoveredRegion - called when the covered region changes. The covered
     * region corresponds to any area of the surface that is covered
     * (transparently or not) by another surface.
     */
    virtual void setCoveredRegion(const Region& coveredRegion);
    void setCoveredRegion(const Region& coveredRegion);

    /*
     * setVisibleNonTransparentRegion - called when the visible and
     * non-transparent region changes.
     */
    virtual void setVisibleNonTransparentRegion(const Region&
    void setVisibleNonTransparentRegion(const Region&
            visibleNonTransparentRegion);

    /*
@@ -238,57 +262,30 @@ public:
     * operation, so this should be set only if needed). Typically this is used
     * to figure out if the content or size of a surface has changed.
     */
    virtual Region latchBuffer(bool& recomputeVisibleRegions);

    /*
     * isOpaque - true if this surface is opaque
     */
    virtual bool isOpaque() const;

    /*
     * isSecure - true if this surface is secure, that is if it prevents
     * screenshots or VNC servers.
     */
    virtual bool isSecure() const           { return mSecure; }

    /*
     * isProtected - true if the layer may contain protected content in the
     * GRALLOC_USAGE_PROTECTED sense.
     */
    virtual bool isProtected() const;

    /*
     * isVisible - true if this layer is visible, false otherwise
     */
    virtual bool isVisible() const;

    /*
     * isFixedSize - true if content has a fixed size
     */
    virtual bool isFixedSize() const;
    Region latchBuffer(bool& recomputeVisibleRegions);

    /*
     * called with the state lock when the surface is removed from the
     * current list
     */
    virtual void onRemoved();
    void onRemoved();


    // Updates the transform hint in our SurfaceFlingerConsumer to match
    // the current orientation of the display device.
    virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const;
    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;
    Rect getContentCrop() const;

    /*
     * returns the transform bits (90 rotation / h-flip / v-flip) of the
     * layer's content
     */
    virtual uint32_t getContentTransform() const;
    uint32_t getContentTransform() const;

    // -----------------------------------------------------------------------

@@ -299,15 +296,15 @@ public:
    // only for debugging
    inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }

    inline  const State&    drawingState() const    { return mDrawingState; }
    inline  const State&    currentState() const    { return mCurrentState; }
    inline  State&          currentState()          { return mCurrentState; }
    inline  const State&    getDrawingState() const { return mDrawingState; }
    inline  const State&    getCurrentState() const { return mCurrentState; }
    inline  State&          getCurrentState()       { return mCurrentState; }


    /* always call base class first */
    virtual void dump(String8& result, Colorizer& colorizer) const;
    virtual void dumpStats(String8& result) const;
    virtual void clearStats();
    void dump(String8& result, Colorizer& colorizer) const;
    void dumpStats(String8& result) const;
    void clearStats();

protected:
    // constant
@@ -333,6 +330,10 @@ private:
    // Interface implementation for SurfaceFlingerConsumer::FrameAvailableListener
    virtual void onFrameAvailable();

    void commitTransaction();

    // needsLinearFiltering - true if this surface's state requires filtering
    bool needsFiltering(const sp<const DisplayDevice>& hw) const;

    uint32_t getEffectiveUsage(uint32_t usage) const;
    Rect computeCrop(const sp<const DisplayDevice>& hw) const;
+2 −2
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ LayerDim::~LayerDim() {

void LayerDim::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const
{
    const State& s(drawingState());
    const State& s(getDrawingState());
    if (s.alpha>0) {
        const GLfloat alpha = s.alpha/255.0f;
        const uint32_t fbHeight = hw->getHeight();
@@ -71,7 +71,7 @@ void LayerDim::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) con
}

bool LayerDim::isVisible() const {
    const Layer::State& s(drawingState());
    const Layer::State& s(getDrawingState());
    return !(s.flags & layer_state_t::eLayerHidden) && s.alpha;
}

+1 −4
Original line number Diff line number Diff line
@@ -36,13 +36,10 @@ public:
                        const String8& name, uint32_t w, uint32_t h, uint32_t flags);
        virtual ~LayerDim();

    virtual const char* getTypeId() const { return "LayerDim"; }
    virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const;
    virtual bool isOpaque() const         { return false; }
    virtual bool isSecure() const         { return false; }
    virtual bool isProtectedByApp() const { return false; }
    virtual bool isProtectedByDRM() const { return false; }
    virtual const char* getTypeId() const { return "LayerDim"; }

    virtual bool isFixedSize() const      { return true; }
    virtual bool isVisible() const;
};
+27 −27
Original line number Diff line number Diff line
@@ -856,10 +856,10 @@ void SurfaceFlinger::doDebugFlashRegions()
void SurfaceFlinger::preComposition()
{
    bool needExtraInvalidate = false;
    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
    const size_t count = currentLayers.size();
    const LayerVector& layers(mDrawingState.layersSortedByZ);
    const size_t count = layers.size();
    for (size_t i=0 ; i<count ; i++) {
        if (currentLayers[i]->onPreComposition()) {
        if (layers[i]->onPreComposition()) {
            needExtraInvalidate = true;
        }
    }
@@ -870,10 +870,10 @@ void SurfaceFlinger::preComposition()

void SurfaceFlinger::postComposition()
{
    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
    const size_t count = currentLayers.size();
    const LayerVector& layers(mDrawingState.layersSortedByZ);
    const size_t count = layers.size();
    for (size_t i=0 ; i<count ; i++) {
        currentLayers[i]->onPostComposition();
        layers[i]->onPostComposition();
    }

    if (mAnimCompositionPending) {
@@ -900,7 +900,7 @@ void SurfaceFlinger::rebuildLayerStacks() {
        mVisibleRegionsDirty = false;
        invalidateHwcGeometry();

        const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
        const LayerVector& layers(mDrawingState.layersSortedByZ);
        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
            Region opaqueRegion;
            Region dirtyRegion;
@@ -909,13 +909,13 @@ void SurfaceFlinger::rebuildLayerStacks() {
            const Transform& tr(hw->getTransform());
            const Rect bounds(hw->getBounds());
            if (hw->canDraw()) {
                SurfaceFlinger::computeVisibleRegions(currentLayers,
                SurfaceFlinger::computeVisibleRegions(layers,
                        hw->getLayerStack(), dirtyRegion, opaqueRegion);

                const size_t count = currentLayers.size();
                const size_t count = layers.size();
                for (size_t i=0 ; i<count ; i++) {
                    const sp<Layer>& layer(currentLayers[i]);
                    const Layer::State& s(layer->drawingState());
                    const sp<Layer>& layer(layers[i]);
                    const Layer::State& s(layer->getDrawingState());
                    if (s.layerStack == hw->getLayerStack()) {
                        Region drawRegion(tr.transform(
                                layer->visibleNonTransparentRegion));
@@ -1257,7 +1257,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
            // layerStack first (so we don't have to traverse the list
            // of displays for every layer).
            const sp<Layer>& layer(currentLayers[i]);
            uint32_t layerStack = layer->drawingState().layerStack;
            uint32_t layerStack = layer->getDrawingState().layerStack;
            if (i==0 || currentlayerStack != layerStack) {
                currentlayerStack = layerStack;
                // figure out if this layerstack is mirrored
@@ -1294,8 +1294,8 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
     * Perform our own transaction if needed
     */

    const LayerVector& previousLayers(mDrawingState.layersSortedByZ);
    if (currentLayers.size() > previousLayers.size()) {
    const LayerVector& layers(mDrawingState.layersSortedByZ);
    if (currentLayers.size() > layers.size()) {
        // layers have been added
        mVisibleRegionsDirty = true;
    }
@@ -1305,15 +1305,15 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
    if (mLayersRemoved) {
        mLayersRemoved = false;
        mVisibleRegionsDirty = true;
        const size_t count = previousLayers.size();
        const size_t count = layers.size();
        for (size_t i=0 ; i<count ; i++) {
            const sp<Layer>& layer(previousLayers[i]);
            const sp<Layer>& layer(layers[i]);
            if (currentLayers.indexOf(layer) < 0) {
                // this layer is not visible anymore
                // TODO: we could traverse the tree from front to back and
                //       compute the actual visible region
                // TODO: we could cache the transformed region
                const Layer::State& s(layer->drawingState());
                const Layer::State& s(layer->getDrawingState());
                Region visibleReg = s.transform.transform(
                        Region(Rect(s.active.w, s.active.h)));
                invalidateLayerStack(s.layerStack, visibleReg);
@@ -1361,7 +1361,7 @@ void SurfaceFlinger::computeVisibleRegions(
        const sp<Layer>& layer = currentLayers[i];

        // start with the whole surface at its current location
        const Layer::State& s(layer->drawingState());
        const Layer::State& s(layer->getDrawingState());

        // only consider the layers on the given layer stack
        if (s.layerStack != layerStack)
@@ -1498,12 +1498,12 @@ void SurfaceFlinger::handlePageFlip()
    Region dirtyRegion;

    bool visibleRegions = false;
    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
    const size_t count = currentLayers.size();
    const LayerVector& layers(mDrawingState.layersSortedByZ);
    const size_t count = layers.size();
    for (size_t i=0 ; i<count ; i++) {
        const sp<Layer>& layer(currentLayers[i]);
        const sp<Layer>& layer(layers[i]);
        const Region dirty(layer->latchBuffer(visibleRegions));
        const Layer::State& s(layer->drawingState());
        const Layer::State& s(layer->getDrawingState());
        invalidateLayerStack(s.layerStack, dirty);
    }

@@ -2705,7 +2705,7 @@ void SurfaceFlinger::renderScreenImplLocked(
    const size_t count = layers.size();
    for (size_t i=0 ; i<count ; ++i) {
        const sp<Layer>& layer(layers[i]);
        const Layer::State& state(layer->drawingState());
        const Layer::State& state(layer->getDrawingState());
        if (state.layerStack == hw->getLayerStack()) {
            if (state.z >= minLayerZ && state.z <= maxLayerZ) {
                if (layer->isVisible()) {
@@ -2872,13 +2872,13 @@ int SurfaceFlinger::LayerVector::do_compare(const void* lhs,
    const sp<Layer>& l(*reinterpret_cast<const sp<Layer>*>(lhs));
    const sp<Layer>& r(*reinterpret_cast<const sp<Layer>*>(rhs));

    uint32_t ls = l->currentState().layerStack;
    uint32_t rs = r->currentState().layerStack;
    uint32_t ls = l->getCurrentState().layerStack;
    uint32_t rs = r->getCurrentState().layerStack;
    if (ls != rs)
        return ls - rs;

    uint32_t lz = l->currentState().z;
    uint32_t rz = r->currentState().z;
    uint32_t lz = l->getCurrentState().z;
    uint32_t rz = r->getCurrentState().z;
    if (lz != rz)
        return lz - rz;