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

Commit ec7ea5ab authored by Alec Mouri's avatar Alec Mouri Committed by Android (Google) Code Review
Browse files

Merge "Fix seaming issue in BitmapRegionDecoder for gainmaps" into main

parents 19037586 edc27eec
Loading
Loading
Loading
Loading
+6 −3
Original line number Original line Diff line number Diff line
@@ -113,7 +113,6 @@ float Properties::maxHdrHeadroomOn8bit = 5.f; // TODO: Refine this number
bool Properties::clipSurfaceViews = false;
bool Properties::clipSurfaceViews = false;
bool Properties::hdr10bitPlus = false;
bool Properties::hdr10bitPlus = false;
bool Properties::skipTelemetry = false;
bool Properties::skipTelemetry = false;
bool Properties::resampleGainmapRegions = false;
bool Properties::queryGlobalPriority = false;
bool Properties::queryGlobalPriority = false;


int Properties::timeoutMultiplier = 1;
int Properties::timeoutMultiplier = 1;
@@ -190,8 +189,6 @@ bool Properties::load() {
    clipSurfaceViews =
    clipSurfaceViews =
            base::GetBoolProperty("debug.hwui.clip_surfaceviews", hwui_flags::clip_surfaceviews());
            base::GetBoolProperty("debug.hwui.clip_surfaceviews", hwui_flags::clip_surfaceviews());
    hdr10bitPlus = hwui_flags::hdr_10bit_plus();
    hdr10bitPlus = hwui_flags::hdr_10bit_plus();
    resampleGainmapRegions = base::GetBoolProperty("debug.hwui.resample_gainmap_regions",
                                                   hwui_flags::resample_gainmap_regions());
    queryGlobalPriority = hwui_flags::query_global_priority();
    queryGlobalPriority = hwui_flags::query_global_priority();


    timeoutMultiplier = android::base::GetIntProperty("ro.hw_timeout_multiplier", 1);
    timeoutMultiplier = android::base::GetIntProperty("ro.hw_timeout_multiplier", 1);
@@ -288,5 +285,11 @@ bool Properties::initializeGlAlways() {
    return base::GetBoolProperty(PROPERTY_INITIALIZE_GL_ALWAYS, hwui_flags::initialize_gl_always());
    return base::GetBoolProperty(PROPERTY_INITIALIZE_GL_ALWAYS, hwui_flags::initialize_gl_always());
}
}


bool Properties::resampleGainmapRegions() {
    static bool sResampleGainmapRegions = base::GetBoolProperty(
            "debug.hwui.resample_gainmap_regions", hwui_flags::resample_gainmap_regions());
    return sResampleGainmapRegions;
}

}  // namespace uirenderer
}  // namespace uirenderer
}  // namespace android
}  // namespace android
+1 −1
Original line number Original line Diff line number Diff line
@@ -345,7 +345,6 @@ public:
    static bool clipSurfaceViews;
    static bool clipSurfaceViews;
    static bool hdr10bitPlus;
    static bool hdr10bitPlus;
    static bool skipTelemetry;
    static bool skipTelemetry;
    static bool resampleGainmapRegions;
    static bool queryGlobalPriority;
    static bool queryGlobalPriority;


    static int timeoutMultiplier;
    static int timeoutMultiplier;
@@ -381,6 +380,7 @@ public:
    static void setDrawingEnabled(bool enable);
    static void setDrawingEnabled(bool enable);


    static bool initializeGlAlways();
    static bool initializeGlAlways();
    static bool resampleGainmapRegions();


private:
private:
    static StretchEffectBehavior stretchEffectBehavior;
    static StretchEffectBehavior stretchEffectBehavior;
+63 −8
Original line number Original line Diff line number Diff line
@@ -112,9 +112,7 @@ public:
            return false;
            return false;
        }
        }


        // Round out the subset so that we decode a slightly larger region, in
        sampleSize = std::max(sampleSize, 1);
        // case the subset has fractional components.
        SkIRect roundedSubset = desiredSubset.roundOut();


        // Map the desired subset to the space of the decoded gainmap. The
        // Map the desired subset to the space of the decoded gainmap. The
        // subset is repositioned relative to the resulting bitmap, and then
        // subset is repositioned relative to the resulting bitmap, and then
@@ -123,10 +121,51 @@ public:
        // for existing gainmap formats.
        // for existing gainmap formats.
        SkRect logicalSubset = desiredSubset.makeOffset(-std::floorf(desiredSubset.left()),
        SkRect logicalSubset = desiredSubset.makeOffset(-std::floorf(desiredSubset.left()),
                                                        -std::floorf(desiredSubset.top()));
                                                        -std::floorf(desiredSubset.top()));
        logicalSubset.fLeft /= sampleSize;
        logicalSubset = scale(logicalSubset, 1.0f / sampleSize);
        logicalSubset.fTop /= sampleSize;

        logicalSubset.fRight /= sampleSize;
        // Round out the subset so that we decode a slightly larger region, in
        logicalSubset.fBottom /= sampleSize;
        // case the subset has fractional components. When we round, we need to
        // round the downsampled subset to avoid possibly rounding down by accident.
        // Consider this concrete example if we round the desired subset directly:
        //
        // * We are decoding a 18x18 corner of an image
        //
        // * Gainmap is 1/4 resolution, which is logically a 4.5x4.5 gainmap
        // that we would want
        //
        // * The app wants to downsample by a factor of 2x
        //
        // * The desired gainmap dimensions are computed to be 3x3 to fit the
        // downsampled gainmap, since we need to fill a 2.25x2.25 region that's
        // later upscaled to 3x3
        //
        // * But, if we round out the desired gainmap region _first_, then we
        // request to decode a 5x5 region, downsampled by 2, which actually
        // decodes a 2x2 region since skia rounds down internally. But then we transfer
        // the result to a 3x3 bitmap using a clipping allocator, which leaves an inset.
        // Not only did we get a smaller region than we expected (so, our desired subset is
        // not valid), but because the API allows for decoding regions using a recycled
        // bitmap, we can't really safely fill in the inset since then we might
        // extend the gainmap beyond intended the image bounds. Oops.
        //
        // * If we instead round out as if we downsampled, then we downsample
        // the desired region to 2.25x2.25, round out to 3x3, then upsample back
        // into the source gainmap space to get 6x6. Then we decode a 6x6 region
        // downsampled into a 3x3 region, and everything's now correct.
        //
        // Note that we don't always run into this problem, because
        // decoders actually round *up* for subsampling when decoding a subset
        // that matches the dimensions of the image. E.g., if the original image
        // size in the above example was a 20x20 image, so that the gainmap was
        // 5x5, then we still manage to downsample into a 3x3 bitmap even with
        // the "wrong" math. but that's what we wanted!
        //
        // Note also that if we overshoot the gainmap bounds with the requested
        // subset it isn't a problem either, since now the decoded bitmap is too
        // large, rather than too small, so now we can use the desired subset to
        // avoid sampling "invalid" colors.
        SkRect scaledSubset = scale(desiredSubset, 1.0f / sampleSize);
        SkIRect roundedSubset = scale(scaledSubset.roundOut(), static_cast<float>(sampleSize));


        RecyclingClippingPixelAllocator allocator(nativeBitmap.get(), false, logicalSubset);
        RecyclingClippingPixelAllocator allocator(nativeBitmap.get(), false, logicalSubset);
        if (!mGainmapBRD->decodeRegion(&bm, &allocator, roundedSubset, sampleSize, decodeColorType,
        if (!mGainmapBRD->decodeRegion(&bm, &allocator, roundedSubset, sampleSize, decodeColorType,
@@ -154,7 +193,7 @@ public:
        const float scaleX = ((float)mGainmapBRD->width()) / mMainImageBRD->width();
        const float scaleX = ((float)mGainmapBRD->width()) / mMainImageBRD->width();
        const float scaleY = ((float)mGainmapBRD->height()) / mMainImageBRD->height();
        const float scaleY = ((float)mGainmapBRD->height()) / mMainImageBRD->height();


        if (uirenderer::Properties::resampleGainmapRegions) {
        if (uirenderer::Properties::resampleGainmapRegions()) {
            const auto srcRect = SkRect::MakeLTRB(
            const auto srcRect = SkRect::MakeLTRB(
                    mainImageRegion.left() * scaleX, mainImageRegion.top() * scaleY,
                    mainImageRegion.left() * scaleX, mainImageRegion.top() * scaleY,
                    mainImageRegion.right() * scaleX, mainImageRegion.bottom() * scaleY);
                    mainImageRegion.right() * scaleX, mainImageRegion.bottom() * scaleY);
@@ -186,6 +225,22 @@ private:
            , mGainmapBRD(std::move(gainmapBRD))
            , mGainmapBRD(std::move(gainmapBRD))
            , mGainmapInfo(info) {}
            , mGainmapInfo(info) {}


    SkRect scale(SkRect rect, float scale) const {
        rect.fLeft *= scale;
        rect.fTop *= scale;
        rect.fRight *= scale;
        rect.fBottom *= scale;
        return rect;
    }

    SkIRect scale(SkIRect rect, float scale) const {
        rect.fLeft *= scale;
        rect.fTop *= scale;
        rect.fRight *= scale;
        rect.fBottom *= scale;
        return rect;
    }

    std::unique_ptr<skia::BitmapRegionDecoder> mMainImageBRD;
    std::unique_ptr<skia::BitmapRegionDecoder> mMainImageBRD;
    std::unique_ptr<skia::BitmapRegionDecoder> mGainmapBRD;
    std::unique_ptr<skia::BitmapRegionDecoder> mGainmapBRD;
    SkGainmapInfo mGainmapInfo;
    SkGainmapInfo mGainmapInfo;
+1 −1
Original line number Original line Diff line number Diff line
@@ -750,7 +750,7 @@ void RecyclingClippingPixelAllocator::copyIfNecessary() {


std::optional<SkRect> RecyclingClippingPixelAllocator::getSourceBoundsForUpsample(
std::optional<SkRect> RecyclingClippingPixelAllocator::getSourceBoundsForUpsample(
        std::optional<SkRect> subset) {
        std::optional<SkRect> subset) {
    if (!uirenderer::Properties::resampleGainmapRegions || !subset || subset->isEmpty()) {
    if (!uirenderer::Properties::resampleGainmapRegions() || !subset || subset->isEmpty()) {
        return std::nullopt;
        return std::nullopt;
    }
    }