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

Commit c875ba73 authored by Winson Chung's avatar Winson Chung
Browse files

Minor optimization to skip bitmap copy during luma sampling

- Attach the hw buffer to an image reader surface and sample
  the bytes directly

Bug: 149318305
Test: Rotate the device and measure the time to get the luma
Change-Id: I50512d6741109ee07a309f840c2936afd19af96e
parent 10e5f365
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.wm;

import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;

import static com.android.server.wm.AnimationSpecProto.ROTATE;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
@@ -36,6 +38,7 @@ import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Trace;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
@@ -205,8 +208,11 @@ class ScreenRotationAnimation {
            SurfaceControl.ScreenshotGraphicBuffer gb =
                    mService.mDisplayManagerInternal.screenshot(displayId);
            if (gb != null) {
                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
                        "ScreenRotationAnimation#getMedianBorderLuma");
                mStartLuma = RotationAnimationUtils.getMedianBorderLuma(gb.getGraphicBuffer(),
                        gb.getColorSpace());
                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                try {
                    surface.attachAndQueueBufferWithColorSpace(gb.getGraphicBuffer(),
                            gb.getColorSpace());
+47 −14
Original line number Diff line number Diff line
@@ -16,16 +16,21 @@

package com.android.server.wm.utils;

import android.graphics.Bitmap;
import static android.graphics.PixelFormat.RGBA_8888;

import android.graphics.Color;
import android.graphics.ColorSpace;
import android.graphics.GraphicBuffer;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.media.Image;
import android.media.ImageReader;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceControl;

import java.nio.ByteBuffer;
import java.util.Arrays;


@@ -38,31 +43,59 @@ public class RotationAnimationUtils {
     * @return the average luminance of all the pixels at the borders of the bitmap
     */
    public static float getMedianBorderLuma(GraphicBuffer graphicBuffer, ColorSpace colorSpace) {
        Bitmap hwBitmap = Bitmap.wrapHardwareBuffer(graphicBuffer, colorSpace);
        if (hwBitmap == null) {
        if (graphicBuffer == null || graphicBuffer.getFormat() != RGBA_8888) {
            return 0;
        }

        Bitmap swaBitmap = hwBitmap.copy(Bitmap.Config.ARGB_8888, false);
        int height = swaBitmap.getHeight();
        int width = swaBitmap.getWidth();
        ImageReader ir = ImageReader.newInstance(graphicBuffer.getWidth(),
                graphicBuffer.getHeight(), graphicBuffer.getFormat(), 1);
        ir.getSurface().attachAndQueueBufferWithColorSpace(graphicBuffer, colorSpace);
        Image image = ir.acquireLatestImage();
        if (image == null || image.getPlanes().length == 0) {
            return 0;
        }

        Image.Plane plane = image.getPlanes()[0];
        ByteBuffer buffer = plane.getBuffer();
        int width = image.getWidth();
        int height = image.getHeight();
        int pixelStride = plane.getPixelStride();
        int rowStride = plane.getRowStride();
        float[] borderLumas = new float[2 * width + 2 * height];
        int i;
        int index = 0;
        for (i = 0; i < width; i++, index += 2) {
            borderLumas[index] = swaBitmap.getColor(i, 0).luminance();
            borderLumas[index + 1] = swaBitmap.getColor(i, height - 1).luminance();

        // Grab the top and bottom borders
        int l = 0;
        for (int x = 0; x < width; x++) {
            borderLumas[l++] = getPixelLuminance(buffer, x, 0, pixelStride, rowStride);
            borderLumas[l++] = getPixelLuminance(buffer, x, height - 1, pixelStride, rowStride);
        }
        for (i = 0; i < height; i++, index += 2) {
            borderLumas[index] = swaBitmap.getColor(0, i).luminance();
            borderLumas[index + 1] = swaBitmap.getColor(width - 1, i).luminance();

        // Grab the left and right borders
        for (int y = 0; y < height; y++) {
            borderLumas[l++] = getPixelLuminance(buffer, 0, y, pixelStride, rowStride);
            borderLumas[l++] = getPixelLuminance(buffer, width - 1, y, pixelStride, rowStride);
        }

        // Cleanup
        ir.close();

        // Oh, is this too simple and inefficient for you?
        // How about implementing a O(n) solution? https://en.wikipedia.org/wiki/Median_of_medians
        Arrays.sort(borderLumas);
        return borderLumas[borderLumas.length / 2];
    }

    private static float getPixelLuminance(ByteBuffer buffer, int x, int y,
            int pixelStride, int rowStride) {
        int offset = y * rowStride + x * pixelStride;
        int pixel = 0;
        pixel |= (buffer.get(offset) & 0xff) << 16;     // R
        pixel |= (buffer.get(offset + 1) & 0xff) << 8;  // G
        pixel |= (buffer.get(offset + 2) & 0xff);       // B
        pixel |= (buffer.get(offset + 3) & 0xff) << 24; // A
        return Color.valueOf(pixel).luminance();
    }

    /**
     * Gets the average border luma by taking a screenshot of the {@param surfaceControl}.
     * @see #getMedianBorderLuma(GraphicBuffer, ColorSpace)