1c3683b552f592d8039a466c663f7de8c8286e975Chris Craik/*
2c3683b552f592d8039a466c663f7de8c8286e975Chris Craik * Copyright (C) 2012 The Android Open Source Project
3c3683b552f592d8039a466c663f7de8c8286e975Chris Craik *
4c3683b552f592d8039a466c663f7de8c8286e975Chris Craik * Licensed under the Apache License, Version 2.0 (the "License");
5c3683b552f592d8039a466c663f7de8c8286e975Chris Craik * you may not use this file except in compliance with the License.
6c3683b552f592d8039a466c663f7de8c8286e975Chris Craik * You may obtain a copy of the License at
7c3683b552f592d8039a466c663f7de8c8286e975Chris Craik *
8c3683b552f592d8039a466c663f7de8c8286e975Chris Craik *      http://www.apache.org/licenses/LICENSE-2.0
9c3683b552f592d8039a466c663f7de8c8286e975Chris Craik *
10c3683b552f592d8039a466c663f7de8c8286e975Chris Craik * Unless required by applicable law or agreed to in writing, software
11c3683b552f592d8039a466c663f7de8c8286e975Chris Craik * distributed under the License is distributed on an "AS IS" BASIS,
12c3683b552f592d8039a466c663f7de8c8286e975Chris Craik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c3683b552f592d8039a466c663f7de8c8286e975Chris Craik * See the License for the specific language governing permissions and
14c3683b552f592d8039a466c663f7de8c8286e975Chris Craik * limitations under the License.
15c3683b552f592d8039a466c663f7de8c8286e975Chris Craik */
16c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
17c3683b552f592d8039a466c663f7de8c8286e975Chris Craikpackage com.android.test.hwuicompare;
18c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
19c3683b552f592d8039a466c663f7de8c8286e975Chris Craikimport com.android.test.hwuicompare.R;
20c3683b552f592d8039a466c663f7de8c8286e975Chris Craikimport com.android.test.hwuicompare.ScriptC_errorCalculator;
21c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
22c3683b552f592d8039a466c663f7de8c8286e975Chris Craikimport android.content.Context;
23c3683b552f592d8039a466c663f7de8c8286e975Chris Craikimport android.content.res.Resources;
24c3683b552f592d8039a466c663f7de8c8286e975Chris Craikimport android.graphics.Bitmap;
25c3683b552f592d8039a466c663f7de8c8286e975Chris Craikimport android.graphics.Color;
26c3683b552f592d8039a466c663f7de8c8286e975Chris Craikimport android.renderscript.Allocation;
27c3683b552f592d8039a466c663f7de8c8286e975Chris Craikimport android.renderscript.Element;
28c3683b552f592d8039a466c663f7de8c8286e975Chris Craikimport android.renderscript.RenderScript;
29c3683b552f592d8039a466c663f7de8c8286e975Chris Craikimport android.util.Log;
30c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
31c3683b552f592d8039a466c663f7de8c8286e975Chris Craikpublic class ErrorCalculator {
32c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    private static final String LOG_TAG = "ErrorCalculator";
33c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    private static final int REGION_SIZE = 8;
34c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
35c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    private static final boolean LOG_TIMING = false;
36c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    private static final boolean LOG_CALC = false;
37c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
38c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    private final RenderScript mRS;
39c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    private Allocation mIdealPixelsAllocation;
40c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    private Allocation mGivenPixelsAllocation;
41c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    private Allocation mOutputPixelsAllocation;
42c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
43c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    private final Allocation mInputRowsAllocation;
44c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    private final Allocation mOutputRegionsAllocation;
45c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
46c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    private final ScriptC_errorCalculator mScript;
47c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
48c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    private final int[] mOutputRowRegions;
49c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
50c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    public ErrorCalculator(Context c, Resources resources) {
51c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        int width = resources.getDimensionPixelSize(R.dimen.layer_width);
52c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        int height = resources.getDimensionPixelSize(R.dimen.layer_height);
53c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mOutputRowRegions = new int[height / REGION_SIZE];
54c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
55c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mRS = RenderScript.create(c);
56c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        int[] rowIndices = new int[height / REGION_SIZE];
57c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        for (int i = 0; i < rowIndices.length; i++)
58c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            rowIndices[i] = i * REGION_SIZE;
59c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
60c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mScript = new ScriptC_errorCalculator(mRS, resources, R.raw.errorcalculator);
61c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mScript.set_HEIGHT(height);
62c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mScript.set_WIDTH(width);
63c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mScript.set_REGION_SIZE(REGION_SIZE);
64c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
65c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mInputRowsAllocation = Allocation.createSized(mRS, Element.I32(mRS), rowIndices.length,
66c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                Allocation.USAGE_SCRIPT);
67c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mInputRowsAllocation.copyFrom(rowIndices);
68c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mOutputRegionsAllocation = Allocation.createSized(mRS, Element.I32(mRS),
69c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                mOutputRowRegions.length, Allocation.USAGE_SCRIPT);
70c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    }
71c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
72c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
73c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    private static long startMillis, middleMillis;
74c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
75c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    public float calcErrorRS(Bitmap ideal, Bitmap given) {
76c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        if (LOG_TIMING) {
77c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            startMillis = System.currentTimeMillis();
78c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        }
79c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
80c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mIdealPixelsAllocation = Allocation.createFromBitmap(mRS, ideal,
81c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
82c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mGivenPixelsAllocation = Allocation.createFromBitmap(mRS, given,
83c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
84c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
85c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mScript.bind_ideal(mIdealPixelsAllocation);
86c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mScript.bind_given(mGivenPixelsAllocation);
87c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
88c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mScript.forEach_countInterestingRegions(mInputRowsAllocation, mOutputRegionsAllocation);
89c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mOutputRegionsAllocation.copyTo(mOutputRowRegions);
90c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
91c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        int regionCount = 0;
92c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        for (int region : mOutputRowRegions) {
93c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            regionCount += region;
94c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        }
95c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        int interestingPixels = Math.max(1, regionCount) * REGION_SIZE * REGION_SIZE;
96c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
97c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        if (LOG_TIMING) {
98c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            long startMillis2 = System.currentTimeMillis();
99c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        }
100c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
101c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mScript.forEach_accumulateError(mInputRowsAllocation, mOutputRegionsAllocation);
102c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mOutputRegionsAllocation.copyTo(mOutputRowRegions);
103c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        float totalError = 0;
104c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        for (int row : mOutputRowRegions) {
105c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            totalError += row;
106c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        }
107c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        totalError /= 1024.0f;
108c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
109c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        if (LOG_TIMING) {
110c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            long finalMillis = System.currentTimeMillis();
111c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            Log.d(LOG_TAG, "rs: first part took " + (middleMillis - startMillis) + "ms");
112c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            Log.d(LOG_TAG, "rs: last part took " + (finalMillis - middleMillis) + "ms");
113c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        }
114c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        if (LOG_CALC) {
115c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            Log.d(LOG_TAG, "rs: error " + totalError + ", pixels " + interestingPixels);
116c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        }
117c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        return totalError / interestingPixels;
118c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    }
119c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
120c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    public void calcErrorHeatmapRS(Bitmap ideal, Bitmap given, Bitmap output) {
121c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mIdealPixelsAllocation = Allocation.createFromBitmap(mRS, ideal,
122c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
123c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mGivenPixelsAllocation = Allocation.createFromBitmap(mRS, given,
124c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
125c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
126c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mScript.bind_ideal(mIdealPixelsAllocation);
127c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mScript.bind_given(mGivenPixelsAllocation);
128c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
129c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mOutputPixelsAllocation = Allocation.createFromBitmap(mRS, output,
130c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
131c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mScript.forEach_displayDifference(mOutputPixelsAllocation, mOutputPixelsAllocation);
132c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        mOutputPixelsAllocation.copyTo(output);
133c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    }
134c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
135c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    public static float calcError(Bitmap ideal, Bitmap given) {
136c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        if (LOG_TIMING) {
137c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            startMillis = System.currentTimeMillis();
138c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        }
139c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
140c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        int interestingRegions = 0;
141c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        for (int x = 0; x < ideal.getWidth(); x += REGION_SIZE) {
142c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            for (int y = 0; y < ideal.getWidth(); y += REGION_SIZE) {
143c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                if (inspectRegion(ideal, x, y)) {
144c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                    interestingRegions++;
145c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                }
146c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            }
147c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        }
148c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
149c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        int interestingPixels = Math.max(1, interestingRegions) * REGION_SIZE * REGION_SIZE;
150c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
151c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        if (LOG_TIMING) {
152c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            long startMillis2 = System.currentTimeMillis();
153c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        }
154c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
155c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        float totalError = 0;
156c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        for (int x = 0; x < ideal.getWidth(); x++) {
157c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            for (int y = 0; y < ideal.getHeight(); y++) {
158c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                int idealColor = ideal.getPixel(x, y);
159c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                int givenColor = given.getPixel(x, y);
160c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                if (idealColor == givenColor)
161c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                    continue;
162c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                totalError += Math.abs(Color.red(idealColor) - Color.red(givenColor));
163c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                totalError += Math.abs(Color.green(idealColor) - Color.green(givenColor));
164c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                totalError += Math.abs(Color.blue(idealColor) - Color.blue(givenColor));
165c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                totalError += Math.abs(Color.alpha(idealColor) - Color.alpha(givenColor));
166c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            }
167c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        }
168c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        totalError /= 1024.0f;
169c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        if (LOG_TIMING) {
170c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            long finalMillis = System.currentTimeMillis();
171c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            Log.d(LOG_TAG, "dvk: first part took " + (middleMillis - startMillis) + "ms");
172c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            Log.d(LOG_TAG, "dvk: last part took " + (finalMillis - middleMillis) + "ms");
173c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        }
174c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        if (LOG_CALC) {
175c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            Log.d(LOG_TAG, "dvk: error " + totalError + ", pixels " + interestingPixels);
176c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        }
177c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        return totalError / interestingPixels;
178c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    }
179c3683b552f592d8039a466c663f7de8c8286e975Chris Craik
180c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    private static boolean inspectRegion(Bitmap ideal, int x, int y) {
181c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        int regionColor = ideal.getPixel(x, y);
182c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        for (int i = 0; i < REGION_SIZE; i++) {
183c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            for (int j = 0; j < REGION_SIZE; j++) {
184c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                if (ideal.getPixel(x + i, y + j) != regionColor)
185c3683b552f592d8039a466c663f7de8c8286e975Chris Craik                    return true;
186c3683b552f592d8039a466c663f7de8c8286e975Chris Craik            }
187c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        }
188c3683b552f592d8039a466c663f7de8c8286e975Chris Craik        return false;
189c3683b552f592d8039a466c663f7de8c8286e975Chris Craik    }
190c3683b552f592d8039a466c663f7de8c8286e975Chris Craik}
191