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

Commit 3cf10956 authored by Vishnu Nair's avatar Vishnu Nair Committed by Android (Google) Code Review
Browse files

Merge "Fix crop scaling with BSL" into sc-dev

parents 9e5a9225 5cc9ac0a
Loading
Loading
Loading
Loading
+11 −7
Original line number Diff line number Diff line
@@ -186,6 +186,7 @@ BLASTBufferQueue::~BLASTBufferQueue() {
void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
                              int32_t format) {
    std::unique_lock _lock{mMutex};
    BQA_LOGV("update width=%d height=%d format=%d", width, height, format);
    if (mFormat != format) {
        mFormat = format;
        mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
@@ -397,10 +398,11 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
    // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
    incStrong((void*)transactionCallbackThunk);

    Rect crop = computeCrop(bufferItem);
    mLastAcquiredFrameNumber = bufferItem.mFrameNumber;
    mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(),
                           bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
                           bufferItem.mScalingMode);
                           bufferItem.mScalingMode, crop);

    auto releaseBufferCallback =
            std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
@@ -415,7 +417,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
    mSurfaceControlsWithPendingCallback.push(mSurfaceControl);

    setMatrix(t, mLastBufferInfo);
    t->setCrop(mSurfaceControl, computeCrop(bufferItem));
    t->setCrop(mSurfaceControl, crop);
    t->setTransform(mSurfaceControl, bufferItem.mTransform);
    t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
    if (!bufferItem.mIsAutoTimestamp) {
@@ -543,13 +545,15 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) {

void BLASTBufferQueue::setMatrix(SurfaceComposerClient::Transaction* t,
                                 const BufferInfo& bufferInfo) {
    uint32_t bufWidth = bufferInfo.width;
    uint32_t bufHeight = bufferInfo.height;
    uint32_t bufWidth = bufferInfo.crop.getWidth();
    uint32_t bufHeight = bufferInfo.crop.getHeight();

    float dsdx = mSize.width / static_cast<float>(bufWidth);
    float dsdy = mSize.height / static_cast<float>(bufHeight);
    float sx = mSize.width / static_cast<float>(bufWidth);
    float sy = mSize.height / static_cast<float>(bufHeight);

    t->setMatrix(mSurfaceControl, dsdx, 0, 0, dsdy);
    t->setMatrix(mSurfaceControl, sx, 0, 0, sy);
    // Update position based on crop.
    t->setPosition(mSurfaceControl, bufferInfo.crop.left * sx * -1, bufferInfo.crop.top * sy * -1);
}

void BLASTBufferQueue::setTransactionCompleteCallback(
+7 −1
Original line number Diff line number Diff line
@@ -151,14 +151,20 @@ private:
        // we get the next buffer. This will support scenarios where the layer can change sizes
        // and the buffer will scale to fit the new size.
        uint32_t scalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
        Rect crop;

        void update(bool hasBuffer, uint32_t width, uint32_t height, uint32_t transform,
                    uint32_t scalingMode) {
                    uint32_t scalingMode, const Rect& crop) {
            this->hasBuffer = hasBuffer;
            this->width = width;
            this->height = height;
            this->transform = transform;
            this->scalingMode = scalingMode;
            if (!crop.isEmpty()) {
                this->crop = crop;
            } else {
                this->crop = Rect(width, height);
            }
        }
    };

+138 −8
Original line number Diff line number Diff line
@@ -522,16 +522,146 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) {
    adapter.waitForCallbacks();
    // capture screen and verify that it is red
    ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
    ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b,
                                               {10, 10, (int32_t)bufferSideLength - 10,
                                                (int32_t)bufferSideLength - 10}));
    ASSERT_NO_FATAL_FAILURE(
            checkScreenCapture(0, 0, 0,
                               {0, 0, (int32_t)bufferSideLength, (int32_t)bufferSideLength},
                               /*border*/ 0, /*outsideRegion*/ true));
}

    Rect bounds;
    bounds.left = finalCropSideLength / 2;
    bounds.top = 0;
    bounds.right = bounds.left + finalCropSideLength;
    bounds.bottom = finalCropSideLength;
TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToBufferSize) {
    // add black background
    auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888,
                                     ISurfaceComposerClient::eFXSurfaceEffect);
    ASSERT_NE(nullptr, bg.get());
    Transaction t;
    t.setLayerStack(bg, 0)
            .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight))
            .setColor(bg, half3{0, 0, 0})
            .setLayer(bg, 0)
            .apply();

    ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b, bounds));
    ASSERT_NO_FATAL_FAILURE(
            checkScreenCapture(0, 0, 0, bounds, /*border*/ 0, /*outsideRegion*/ true));
    Rect windowSize(1000, 1000);
    Rect bufferSize(windowSize);
    Rect bufferCrop(200, 200, 700, 700);

    BLASTBufferQueueHelper adapter(mSurfaceControl, windowSize.getWidth(), windowSize.getHeight());
    sp<IGraphicBufferProducer> igbProducer;
    setUpProducer(adapter, igbProducer);
    int slot;
    sp<Fence> fence;
    sp<GraphicBuffer> buf;
    auto ret = igbProducer->dequeueBuffer(&slot, &fence, bufferSize.getWidth(),
                                          bufferSize.getHeight(), PIXEL_FORMAT_RGBA_8888,
                                          GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr);
    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
    ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf));

    uint32_t* bufData;
    buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN),
              reinterpret_cast<void**>(&bufData));
    // fill buffer with grey
    fillBuffer(bufData, bufferSize, buf->getStride(), 127, 127, 127);

    // fill crop area with different colors so we can verify the cropped region has been scaled
    // correctly.
    fillBuffer(bufData, Rect(200, 200, 450, 450), buf->getStride(), /* rgb */ 255, 0, 0);
    fillBuffer(bufData, Rect(200, 451, 450, 700), buf->getStride(), /* rgb */ 0, 255, 0);
    fillBuffer(bufData, Rect(451, 200, 700, 450), buf->getStride(), /* rgb */ 0, 0, 255);
    fillBuffer(bufData, Rect(451, 451, 700, 700), buf->getStride(), /* rgb */ 255, 0, 0);
    buf->unlock();

    IGraphicBufferProducer::QueueBufferOutput qbOutput;
    IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */,
                                                   HAL_DATASPACE_UNKNOWN,
                                                   bufferCrop /* Rect::INVALID_RECT */,
                                                   NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, 0,
                                                   Fence::NO_FENCE);
    igbProducer->queueBuffer(slot, input, &qbOutput);
    ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);

    adapter.waitForCallbacks();

    ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));

    // Verify cropped region is scaled correctly.
    ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {10, 10, 490, 490}));
    ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 255, 0, {10, 510, 490, 990}));
    ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 255, {510, 10, 990, 490}));
    ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {510, 510, 990, 990}));
    // Verify outside region is black.
    ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 0,
                                               {0, 0, (int32_t)windowSize.getWidth(),
                                                (int32_t)windowSize.getHeight()},
                                               /*border*/ 0, /*outsideRegion*/ true));
}

TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToWindowSize) {
    // add black background
    auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888,
                                     ISurfaceComposerClient::eFXSurfaceEffect);
    ASSERT_NE(nullptr, bg.get());
    Transaction t;
    t.setLayerStack(bg, 0)
            .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight))
            .setColor(bg, half3{0, 0, 0})
            .setLayer(bg, 0)
            .apply();

    Rect windowSize(1000, 1000);
    Rect bufferSize(500, 500);
    Rect bufferCrop(100, 100, 350, 350);

    BLASTBufferQueueHelper adapter(mSurfaceControl, windowSize.getWidth(), windowSize.getHeight());
    sp<IGraphicBufferProducer> igbProducer;
    setUpProducer(adapter, igbProducer);
    int slot;
    sp<Fence> fence;
    sp<GraphicBuffer> buf;
    auto ret = igbProducer->dequeueBuffer(&slot, &fence, bufferSize.getWidth(),
                                          bufferSize.getHeight(), PIXEL_FORMAT_RGBA_8888,
                                          GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr);
    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
    ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf));

    uint32_t* bufData;
    buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN),
              reinterpret_cast<void**>(&bufData));
    // fill buffer with grey
    fillBuffer(bufData, bufferSize, buf->getStride(), 127, 127, 127);

    // fill crop area with different colors so we can verify the cropped region has been scaled
    // correctly.
    fillBuffer(bufData, Rect(100, 100, 225, 225), buf->getStride(), /* rgb */ 255, 0, 0);
    fillBuffer(bufData, Rect(100, 226, 225, 350), buf->getStride(), /* rgb */ 0, 255, 0);
    fillBuffer(bufData, Rect(226, 100, 350, 225), buf->getStride(), /* rgb */ 0, 0, 255);
    fillBuffer(bufData, Rect(226, 226, 350, 350), buf->getStride(), /* rgb */ 255, 0, 0);
    buf->unlock();

    IGraphicBufferProducer::QueueBufferOutput qbOutput;
    IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */,
                                                   HAL_DATASPACE_UNKNOWN,
                                                   bufferCrop /* Rect::INVALID_RECT */,
                                                   NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, 0,
                                                   Fence::NO_FENCE);
    igbProducer->queueBuffer(slot, input, &qbOutput);
    ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);

    adapter.waitForCallbacks();

    ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
    // Verify cropped region is scaled correctly.
    ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {10, 10, 490, 490}));
    ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 255, 0, {10, 510, 490, 990}));
    ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 255, {510, 10, 990, 490}));
    ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {510, 510, 990, 990}));
    // Verify outside region is black.
    ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 0,
                                               {0, 0, (int32_t)windowSize.getWidth(),
                                                (int32_t)windowSize.getHeight()},
                                               /*border*/ 0, /*outsideRegion*/ true));
}

class TestProducerListener : public BnProducerListener {
+4 −20
Original line number Diff line number Diff line
@@ -790,7 +790,7 @@ void BufferStateLayer::gatherBufferInfo() {
    mBufferInfo.mFence = s.acquireFence;
    mBufferInfo.mTransform = s.bufferTransform;
    mBufferInfo.mDataspace = translateDataspace(s.dataspace);
    mBufferInfo.mCrop = computeCrop(s);
    mBufferInfo.mCrop = computeBufferCrop(s);
    mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
    mBufferInfo.mSurfaceDamage = s.surfaceDamageRegion;
    mBufferInfo.mHdrMetadata = s.hdrMetadata;
@@ -803,27 +803,11 @@ uint32_t BufferStateLayer::getEffectiveScalingMode() const {
   return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
}

Rect BufferStateLayer::computeCrop(const State& s) {
    if (s.crop.isEmpty() && s.buffer) {
Rect BufferStateLayer::computeBufferCrop(const State& s) {
    if (s.buffer) {
        return s.buffer->getBuffer()->getBounds();
    } else if (s.buffer) {
        Rect crop = s.crop;
        crop.left = std::max(crop.left, 0);
        crop.top = std::max(crop.top, 0);
        uint32_t bufferWidth = s.buffer->getBuffer()->getWidth();
        uint32_t bufferHeight = s.buffer->getBuffer()->getHeight();
        if (bufferHeight <= std::numeric_limits<int32_t>::max() &&
            bufferWidth <= std::numeric_limits<int32_t>::max()) {
            crop.right = std::min(crop.right, static_cast<int32_t>(bufferWidth));
            crop.bottom = std::min(crop.bottom, static_cast<int32_t>(bufferHeight));
        }
        if (!crop.isValid()) {
            // Crop rect is out of bounds, return whole buffer
            return s.buffer->getBuffer()->getBounds();
        }
        return crop;
    }
    return s.crop;
    return Rect::INVALID_RECT;
}

sp<Layer> BufferStateLayer::createClone() {
+1 −1
Original line number Diff line number Diff line
@@ -140,7 +140,7 @@ private:
    sp<Layer> createClone() override;

    // Crop that applies to the buffer
    Rect computeCrop(const State& s);
    Rect computeBufferCrop(const State& s);

    bool willPresentCurrentTransaction() const;