• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.uirendering.cts.testclasses;
18 
19 import static junit.framework.Assert.assertFalse;
20 
21 import static org.testng.Assert.assertEquals;
22 import static org.testng.Assert.assertTrue;
23 
24 import android.graphics.Bitmap;
25 import android.graphics.BitmapShader;
26 import android.graphics.Canvas;
27 import android.graphics.Color;
28 import android.graphics.ColorSpace;
29 import android.graphics.Gainmap;
30 import android.graphics.HardwareBufferRenderer;
31 import android.graphics.Matrix;
32 import android.graphics.Paint;
33 import android.graphics.Picture;
34 import android.graphics.RecordingCanvas;
35 import android.graphics.RenderNode;
36 import android.graphics.Shader;
37 import android.hardware.HardwareBuffer;
38 import android.platform.test.annotations.RequiresFlagsEnabled;
39 import android.platform.test.flag.junit.CheckFlagsRule;
40 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
41 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
42 import android.uirendering.cts.util.BitmapAsserter;
43 import android.uirendering.cts.util.BitmapDumper;
44 
45 import androidx.annotation.ColorLong;
46 import androidx.test.filters.SmallTest;
47 import androidx.test.runner.AndroidJUnit4;
48 
49 import com.android.graphics.hwui.flags.Flags;
50 
51 import org.junit.Rule;
52 import org.junit.Test;
53 import org.junit.runner.RunWith;
54 import org.testng.Assert;
55 
56 import java.util.concurrent.CountDownLatch;
57 import java.util.concurrent.TimeUnit;
58 import java.util.function.Consumer;
59 
60 @SmallTest
61 @RunWith(AndroidJUnit4.class)
62 public class GainmapTests {
63 
64     @Rule
65     public final CheckFlagsRule mCheckFlagsRule =
66             DeviceFlagsValueProvider.createCheckFlagsRule();
67 
68 
69     private static final ColorSpace BT2020_HLG = ColorSpace.get(ColorSpace.Named.BT2020_HLG);
70     private static final ColorSpace BT2020_PQ = ColorSpace.get(ColorSpace.Named.BT2020_PQ);
71     private static final ColorSpace BT2020 = ColorSpace.get(ColorSpace.Named.BT2020);
72     private static final ColorSpace SRGB = ColorSpace.get(ColorSpace.Named.SRGB);
73 
74     // A 10x6 base image with a 5x3 (so 1/2 res) gainmap that boosts the center 3 pixels
75     // by 0x40, 0x80, and 0xff respectively
76     private static final Bitmap sTestImage;
77     static {
78         Bitmap base = Bitmap.createBitmap(10, 6, Bitmap.Config.ARGB_8888);
79         base.eraseColor(Color.WHITE);
80 
81         Bitmap gainmapImage = Bitmap.createBitmap(5, 3, Bitmap.Config.ARGB_8888);
82         gainmapImage.eraseColor(0);
83         gainmapImage.setPixel(1, 1, 0xFF404040);
84         gainmapImage.setPixel(2, 1, 0xFF808080);
85         gainmapImage.setPixel(3, 1, 0xFFFFFFFF);
86 
87         Gainmap gainmap = new Gainmap(gainmapImage);
88         base.setGainmap(gainmap);
89         sTestImage = base;
90     }
91 
92     // A 10x6 HLG base image with a 1x1 gainmap that annihilates the red and blue
93     // components in an sRGB working space.
94     private static final Bitmap sHLGTestImage;
95     static {
96         Bitmap base = Bitmap.createBitmap(10, 6, Bitmap.Config.ARGB_8888);
97         base.eraseColor(Color.WHITE);
98         base.setColorSpace(BT2020_HLG);
99 
100         Bitmap gainmapImage = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
101         gainmapImage.setPixel(0, 0, 0xFFFF00FF);
102         Gainmap gainmap = new Gainmap(gainmapImage);
103         if (Flags.isoGainmapApis()) {
104             gainmap.setGainmapDirection(Gainmap.GAINMAP_DIRECTION_HDR_TO_SDR);
105             gainmap.setAlternativeImagePrimaries(SRGB);
106         }
107         gainmap.setRatioMax(100000000f, 100000000f, 100000000f);
108         gainmap.setRatioMin(3.789f, 3.789f, 3.789f);
109         base.setGainmap(gainmap);
110         sHLGTestImage = base;
111     }
112 
113     // A 10x6 base image with a 5x3 (so 1/2 res) gainmap that boosts the center 3 pixels
114     // by 0x40, 0x80, and 0xff respectively
115     private static final Bitmap sTestImageA8;
116     static {
117         Bitmap base = Bitmap.createBitmap(10, 6, Bitmap.Config.ARGB_8888);
118         base.eraseColor(Color.WHITE);
119 
120         Bitmap gainmapImage = Bitmap.createBitmap(5, 3, Bitmap.Config.ALPHA_8);
121         gainmapImage.eraseColor(0);
122         gainmapImage.setPixel(1, 1, 0x40000000);
123         gainmapImage.setPixel(2, 1, 0x80000000);
124         gainmapImage.setPixel(3, 1, 0xFF000000);
125 
126         Gainmap gainmap = new Gainmap(gainmapImage);
127         base.setGainmap(gainmap);
128         sTestImageA8 = base;
129     }
130 
131     private static final Picture sTestPicture;
132     static {
133         sTestPicture = new Picture();
134         Canvas canvas = sTestPicture.beginRecording(sTestImage.getWidth(), sTestImage.getHeight());
canvas.drawBitmap(sTestImage, 0, 0, null)135         canvas.drawBitmap(sTestImage, 0, 0, null);
sTestPicture.endRecording()136         sTestPicture.endRecording();
137     }
138 
139     private static final Picture sHLGTestPicture;
140     static {
141         sHLGTestPicture = new Picture();
142         Canvas canvas = sHLGTestPicture.beginRecording(
143                 sHLGTestImage.getWidth(), sHLGTestImage.getHeight());
canvas.drawBitmap(sHLGTestImage, 0, 0, null)144         canvas.drawBitmap(sHLGTestImage, 0, 0, null);
sHLGTestPicture.endRecording()145         sHLGTestPicture.endRecording();
146     }
147 
148     private static final Gainmap sNoOpGainmap;
149     static {
150         sNoOpGainmap = new Gainmap(Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8));
151         sNoOpGainmap.setRatioMin(1f, 1f, 1f);
152         sNoOpGainmap.setRatioMax(1f, 1f, 1f);
153     }
154 
assertChannels(Color result, @ColorLong long expected, float delta)155     private static void assertChannels(Color result, @ColorLong long expected, float delta) {
156         ColorSpace.Connector connector = ColorSpace.connect(Color.colorSpace(expected),
157                 result.getColorSpace());
158         float[] mapped = connector.transform(Color.red(expected), Color.green(expected),
159                 Color.blue(expected));
160         Assert.assertEquals(result.red(), mapped[0], delta, "red channel mismatch");
161         Assert.assertEquals(result.green(), mapped[1], delta, "green channel mismatch");
162         Assert.assertEquals(result.blue(), mapped[2], delta, "blue channel mismatch");
163     }
164 
165     @ColorLong
mapWhiteWithGain(Gainmap gainmap, double gain)166     private static long mapWhiteWithGain(Gainmap gainmap, double gain) {
167         double logRatioMin = Math.log(gainmap.getRatioMin()[0]);
168         double logRatioMax = Math.log(gainmap.getRatioMax()[0]);
169         double epsilonSdr = gainmap.getEpsilonSdr()[0];
170         double epsilonHdr = gainmap.getEpsilonHdr()[0];
171         double L = (logRatioMin * (1 - gain)) + (logRatioMax * gain);
172         float D = (float) ((1.0 + epsilonSdr) * Math.exp(L) - epsilonHdr);
173         return Color.pack(D, D, D, 1.f, ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB));
174     }
175 
assertTestImageResult(Bitmap result)176     private void assertTestImageResult(Bitmap result) {
177         assertTestImageResult(result, sTestImage.getGainmap());
178     }
179 
toleranceForResult(Bitmap result)180     private static float toleranceForResult(Bitmap result) {
181         // 8888 precision ain't so great
182         if (result.getConfig() == Bitmap.Config.ARGB_8888) {
183             // PQ math on GLES2.0 is very poor
184             if (result.getColorSpace().getId() == ColorSpace.Named.BT2020_PQ.ordinal()
185                     || result.getColorSpace().getId() == ColorSpace.Named.BT2020.ordinal()) {
186                 return 0.06f;
187             }
188             return 0.02f;
189         }
190         return 0.004f;
191     }
192 
assertTestImageResult(Bitmap result, Gainmap gainmap)193     private void assertTestImageResult(Bitmap result, Gainmap gainmap) {
194         try {
195             // 8888 precision ain't so great
196             final float delta = toleranceForResult(result);
197             assertChannels(result.getColor(0, 0), Color.pack(Color.WHITE), delta);
198             assertChannels(result.getColor(2, 2),
199                     mapWhiteWithGain(gainmap, 0x40 / 255.f), delta);
200             assertChannels(result.getColor(4, 2),
201                     mapWhiteWithGain(gainmap, 0x80 / 255.f), delta);
202             assertChannels(result.getColor(6, 2),
203                     mapWhiteWithGain(gainmap, 0xFF / 255.f), delta);
204         } catch (Throwable t) {
205             BitmapDumper.dumpBitmap(result);
206             throw t;
207         }
208     }
209 
assertFullyAppliedHLGTestImageResult(Bitmap result)210     private void assertFullyAppliedHLGTestImageResult(Bitmap result) {
211         try {
212             final float delta = toleranceForResult(result);
213             // Note: maps a BT. 2020 color to an sRGB Green
214             assertChannels(result.getColor(0, 0), Color.pack(Color.GREEN), delta);
215             assertChannels(result.getColor(2, 2), Color.pack(Color.GREEN), delta);
216             assertChannels(result.getColor(4, 2), Color.pack(Color.GREEN), delta);
217             assertChannels(result.getColor(6, 2), Color.pack(Color.GREEN), delta);
218         } catch (Throwable t) {
219             BitmapDumper.dumpBitmap(result);
220             throw t;
221         }
222     }
223 
renderTestImageWithHardware(ColorSpace dest)224     private static Bitmap renderTestImageWithHardware(ColorSpace dest) {
225         return renderTestImageWithHardware(dest, false);
226     }
227 
renderWithHardware(ColorSpace dest, Consumer<RecordingCanvas> func)228     private static Bitmap renderWithHardware(ColorSpace dest, Consumer<RecordingCanvas> func) {
229         HardwareBuffer buffer = HardwareBuffer.create(sTestImage.getWidth(), sTestImage.getHeight(),
230                 HardwareBuffer.RGBA_8888,
231                 1, HardwareBuffer.USAGE_GPU_COLOR_OUTPUT | HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
232         HardwareBufferRenderer renderer = new HardwareBufferRenderer(buffer);
233         RenderNode content = new RenderNode("gainmap");
234         content.setPosition(0, 0, sTestImage.getWidth(), sTestImage.getHeight());
235         RecordingCanvas canvas = content.beginRecording();
236         func.accept(canvas);
237         content.endRecording();
238         renderer.setContentRoot(content);
239         CountDownLatch latch = new CountDownLatch(1);
240         renderer.obtainRenderRequest().setColorSpace(dest).draw(Runnable::run, result -> {
241             result.getFence().awaitForever();
242             latch.countDown();
243         });
244         try {
245             Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
246         } catch (InterruptedException ex) {
247             Assert.fail(ex.getMessage());
248         }
249         return Bitmap.wrapHardwareBuffer(buffer, dest).copy(Bitmap.Config.ARGB_8888, false);
250     }
251 
renderTestImageWithHardware(Bitmap bitmap, ColorSpace dest)252     private static Bitmap renderTestImageWithHardware(Bitmap bitmap, ColorSpace dest) {
253         return renderWithHardware(dest, canvas -> {
254             canvas.drawBitmap(bitmap, 0, 0, null);
255         });
256     }
257 
renderTestPictureWithHardware(Picture picture, ColorSpace dest)258     private static Bitmap renderTestPictureWithHardware(Picture picture, ColorSpace dest) {
259         return renderWithHardware(dest, canvas -> {
260             canvas.drawPicture(picture);
261         });
262     }
263 
264     private static Bitmap renderTestImageWithHardware(ColorSpace dest, boolean usePicture) {
265         if (usePicture) {
266             return renderTestPictureWithHardware(sTestPicture, dest);
267         } else {
268             return renderTestImageWithHardware(sTestImage, dest);
269         }
270     }
271 
272     @Test
273     public void gainmapToHlgSoftware() {
274         Bitmap result = Bitmap.createBitmap(10, 6, Bitmap.Config.RGBA_F16, false, BT2020_HLG);
275         Canvas canvas = new Canvas(result);
276         canvas.drawBitmap(sTestImage, 0f, 0f, null);
277         assertTestImageResult(result);
278         canvas.drawBitmap(sTestImageA8, 0f, 0f, null);
279         assertTestImageResult(result);
280     }
281 
282     @Test
283     public void gainmapToPqSoftware() {
284         Bitmap result = Bitmap.createBitmap(10, 6, Bitmap.Config.RGBA_F16, false, BT2020_PQ);
285         Canvas canvas = new Canvas(result);
286         canvas.drawBitmap(sTestImage, 0f, 0f, null);
287         assertTestImageResult(result);
288         canvas.drawBitmap(sTestImageA8, 0f, 0f, null);
289         assertTestImageResult(result);
290     }
291 
292     @Test
293     public void gainmapToSrgbSoftware() {
294         Bitmap result = Bitmap.createBitmap(10, 6, Bitmap.Config.RGBA_F16, false, SRGB);
295         Canvas canvas = new Canvas(result);
296         canvas.drawBitmap(sTestImage, 0f, 0f, null);
297         assertTestImageResult(result, sNoOpGainmap);
298     }
299 
300     @RequiresFlagsEnabled(Flags.FLAG_ISO_GAINMAP_APIS)
301     @Test
302     public void hlgGainmapToBt2020Software() {
303         Bitmap result = Bitmap.createBitmap(10, 6, Bitmap.Config.RGBA_F16, false, BT2020);
304         Canvas canvas = new Canvas(result);
305         canvas.drawBitmap(sHLGTestImage, 0f, 0f, null);
306         assertFullyAppliedHLGTestImageResult(result);
307     }
308 
309     @Test
310     public void gainmapToHlgPictureSoftware() {
311         Bitmap result = Bitmap.createBitmap(10, 6, Bitmap.Config.RGBA_F16, false, BT2020_HLG);
312         Canvas canvas = new Canvas(result);
313         canvas.drawPicture(sTestPicture);
314         assertTestImageResult(result);
315     }
316 
317     @Test
318     public void gainmapToPqPictureSoftware() {
319         Bitmap result = Bitmap.createBitmap(10, 6, Bitmap.Config.RGBA_F16, false, BT2020_HLG);
320         Canvas canvas = new Canvas(result);
321         canvas.drawPicture(sTestPicture);
322         assertTestImageResult(result);
323     }
324 
325     @Test
326     public void gainmapToSrgbPictureSoftware() {
327         Bitmap result = Bitmap.createBitmap(10, 6, Bitmap.Config.RGBA_F16, false, SRGB);
328         Canvas canvas = new Canvas(result);
329         canvas.drawPicture(sTestPicture);
330         assertTestImageResult(result, sNoOpGainmap);
331     }
332 
333     @RequiresFlagsEnabled(Flags.FLAG_ISO_GAINMAP_APIS)
334     @Test
335     public void hlgGainmapToBt2020PictureSoftware() {
336         Bitmap result = Bitmap.createBitmap(10, 6, Bitmap.Config.RGBA_F16, false, BT2020);
337         Canvas canvas = new Canvas(result);
338         canvas.drawPicture(sHLGTestPicture);
339         assertFullyAppliedHLGTestImageResult(result);
340     }
341 
342     @Test
343     public void gainmapToHlgHardware() throws Exception {
344         Bitmap result = renderTestImageWithHardware(BT2020_HLG);
345         assertTestImageResult(result);
346     }
347 
348     @Test
349     public void gainmapToPqHardware() {
350         Bitmap result = renderTestImageWithHardware(BT2020_PQ);
351         assertTestImageResult(result);
352     }
353 
354     @Test
355     public void gainmapToSrgbHardware() {
356         Bitmap result = renderTestImageWithHardware(SRGB);
357         assertTestImageResult(result, sNoOpGainmap);
358     }
359 
360     @RequiresFlagsEnabled(Flags.FLAG_ISO_GAINMAP_APIS)
361     @Test
362     public void hlgGainmapToBt2020Hardware() {
363         Bitmap result = renderTestImageWithHardware(sHLGTestImage, BT2020);
364         assertFullyAppliedHLGTestImageResult(result);
365     }
366 
367     @Test
368     public void gainmapToHlgPictureHardware() throws Exception {
369         Bitmap result = renderTestImageWithHardware(BT2020_HLG, true);
370         assertTestImageResult(result);
371     }
372 
373     @Test
374     public void gainmapToPqPictureHardware() {
375         Bitmap result = renderTestImageWithHardware(BT2020_PQ, true);
376         assertTestImageResult(result);
377     }
378 
379     @Test
380     public void gainmapToSrgbPictureHardware() {
381         Bitmap result = renderTestImageWithHardware(SRGB, true);
382         assertTestImageResult(result, sNoOpGainmap);
383     }
384 
385     @RequiresFlagsEnabled(Flags.FLAG_ISO_GAINMAP_APIS)
386     @Test
387     public void hlgGainmapToBt2020PictureHardware() {
388         Bitmap result = renderTestPictureWithHardware(sHLGTestPicture, BT2020);
389         assertFullyAppliedHLGTestImageResult(result);
390     }
391 
392     @Test
393     public void bitmapShaderSupportHLG() {
394         Bitmap result = Bitmap.createBitmap(10, 6, Bitmap.Config.RGBA_F16, false, BT2020_HLG);
395         Canvas canvas = new Canvas(result);
396         Paint paint = new Paint();
397         paint.setFlags(0);
398         BitmapShader shader = new BitmapShader(sTestImage, Shader.TileMode.CLAMP,
399                 Shader.TileMode.CLAMP);
400         paint.setShader(shader);
401         canvas.drawPaint(paint);
402         assertTestImageResult(result);
403     }
404 
405     @RequiresFlagsEnabled(Flags.FLAG_ISO_GAINMAP_APIS)
406     @Test
407     public void bitmapShaderSupportHLGGainmaps() {
408         Bitmap result = Bitmap.createBitmap(10, 6, Bitmap.Config.RGBA_F16, false, BT2020);
409         Canvas canvas = new Canvas(result);
410         Paint paint = new Paint();
411         paint.setFlags(0);
412         BitmapShader shader = new BitmapShader(sHLGTestImage, Shader.TileMode.CLAMP,
413                 Shader.TileMode.CLAMP);
414         paint.setShader(shader);
415         canvas.drawPaint(paint);
416         assertFullyAppliedHLGTestImageResult(result);
417     }
418 
419     @Test
420     public void bitmapShaderSupportHLGHardware() {
421         Bitmap result = renderWithHardware(BT2020_HLG, canvas -> {
422             Paint paint = new Paint();
423             paint.setFlags(0);
424             BitmapShader shader = new BitmapShader(sTestImage, Shader.TileMode.CLAMP,
425                     Shader.TileMode.CLAMP);
426             paint.setShader(shader);
427             canvas.drawPaint(paint);
428         });
429         assertTestImageResult(result);
430     }
431 
432     @Test
433     public void bitmapShaderSupportSrgbHardware() {
434         Bitmap result = renderWithHardware(SRGB, canvas -> {
435             Paint paint = new Paint();
436             paint.setFlags(0);
437             BitmapShader shader = new BitmapShader(sTestImage, Shader.TileMode.CLAMP,
438                     Shader.TileMode.CLAMP);
439             paint.setShader(shader);
440             canvas.drawPaint(paint);
441         });
442         assertTestImageResult(result, sNoOpGainmap);
443     }
444 
445     @RequiresFlagsEnabled(Flags.FLAG_ISO_GAINMAP_APIS)
446     @Test
447     public void bitmapShaderSupportHLGGainmapsHardware() {
448         Bitmap result = renderWithHardware(BT2020, canvas -> {
449             Paint paint = new Paint();
450             paint.setFlags(0);
451             BitmapShader shader = new BitmapShader(sHLGTestImage, Shader.TileMode.CLAMP,
452                     Shader.TileMode.CLAMP);
453             paint.setShader(shader);
454             canvas.drawPaint(paint);
455         });
456         assertFullyAppliedHLGTestImageResult(result);
457     }
458 
459 
460     @RequiresFlagsEnabled(Flags.FLAG_GAINMAP_ANIMATIONS)
461     @Test
462     public void bitmapShaderOverrideGainmapToNoOpHLG() {
463         Bitmap result = Bitmap.createBitmap(10, 6, Bitmap.Config.RGBA_F16, false, BT2020_HLG);
464         Canvas canvas = new Canvas(result);
465         Paint paint = new Paint();
466         paint.setFlags(0);
467         BitmapShader shader = new BitmapShader(sTestImage, Shader.TileMode.CLAMP,
468                 Shader.TileMode.CLAMP);
469         shader.setOverrideGainmap(sNoOpGainmap);
470         paint.setShader(shader);
471         canvas.drawPaint(paint);
472         BitmapAsserter.assertBitmapIsVerified(result, new ColorVerifier(Color.WHITE, 3),
473                 "");
474     }
475 
476     @RequiresFlagsEnabled(Flags.FLAG_GAINMAP_ANIMATIONS)
477     @Test
478     public void bitmapShaderOverrideGainmapTo4xHLG() {
479         Gainmap override = new Gainmap(sTestImage.getGainmap().getGainmapContents());
480         override.setRatioMax(4.0f, 4.0f, 4.0f);
481         Bitmap result = Bitmap.createBitmap(10, 6, Bitmap.Config.RGBA_F16, false, BT2020_HLG);
482         Canvas canvas = new Canvas(result);
483         Paint paint = new Paint();
484         paint.setFlags(0);
485         BitmapShader shader = new BitmapShader(sTestImage, Shader.TileMode.CLAMP,
486                 Shader.TileMode.CLAMP);
487         shader.setOverrideGainmap(override);
488         paint.setShader(shader);
489         canvas.drawPaint(paint);
490         assertTestImageResult(result, override);
491     }
492 
493     @RequiresFlagsEnabled(Flags.FLAG_GAINMAP_ANIMATIONS)
494     @Test
495     public void bitmapShaderOverrideGainmapModifyAfterSetHLG() {
496         Gainmap override = new Gainmap(sTestImage.getGainmap().getGainmapContents());
497         override.setRatioMax(4.0f, 4.0f, 4.0f);
498         Gainmap initialOverride = new Gainmap(override, override.getGainmapContents());
499         Bitmap result = Bitmap.createBitmap(10, 6, Bitmap.Config.RGBA_F16, false, BT2020_HLG);
500         Canvas canvas = new Canvas(result);
501         Paint paint = new Paint();
502         paint.setFlags(0);
503         BitmapShader shader = new BitmapShader(sTestImage, Shader.TileMode.CLAMP,
504                 Shader.TileMode.CLAMP);
505         shader.setOverrideGainmap(override);
506         override.setRatioMax(1f, 1f, 1f);
507         paint.setShader(shader);
508         canvas.drawPaint(paint);
509         assertTestImageResult(result, initialOverride);
510     }
511 
512     @RequiresFlagsEnabled(Flags.FLAG_GAINMAP_ANIMATIONS)
513     @Test
514     public void bitmapShaderOverrideGainmapPaintObservesUpdatesHLG() {
515         Gainmap override = new Gainmap(sTestImage.getGainmap().getGainmapContents());
516         Bitmap result = Bitmap.createBitmap(10, 6, Bitmap.Config.RGBA_F16, false, BT2020_HLG);
517         Canvas canvas = new Canvas(result);
518         Paint paint = new Paint();
519         paint.setFlags(0);
520         BitmapShader shader = new BitmapShader(sTestImage, Shader.TileMode.CLAMP,
521                 Shader.TileMode.CLAMP);
522         shader.setOverrideGainmap(override);
523         paint.setShader(shader);
524         canvas.drawPaint(paint);
525         override.setRatioMax(1, 1, 1);
526         shader.setOverrideGainmap(override);
527         canvas.drawPaint(paint);
528         BitmapAsserter.assertBitmapIsVerified(result, new ColorVerifier(Color.WHITE, 3),
529                 "");
530     }
531 
532     @Test
533     public void createScaledBitmap() {
534         Bitmap result = Bitmap.createScaledBitmap(sTestImage, 20, 12, false);
535         assertEquals(result.getWidth(), 20);
536         assertEquals(result.getHeight(), 12);
537         assertTrue(result.hasGainmap());
538         Bitmap gainmapContents = result.getGainmap().getGainmapContents();
539         assertEquals(gainmapContents.getWidth(), 10);
540         assertEquals(gainmapContents.getHeight(), 6);
541 
542         assertChannels(gainmapContents.getColor(0, 0), Color.pack(Color.BLACK), 0f);
543         assertChannels(gainmapContents.getColor(1, 1), Color.pack(Color.BLACK), 0f);
544 
545         assertChannels(gainmapContents.getColor(2, 2), Color.pack(0xFF404040), 0f);
546         assertChannels(gainmapContents.getColor(3, 3), Color.pack(0xFF404040), 0f);
547 
548         assertChannels(gainmapContents.getColor(4, 2), Color.pack(0xFF808080), 0f);
549         assertChannels(gainmapContents.getColor(5, 3), Color.pack(0xFF808080), 0f);
550 
551         assertChannels(gainmapContents.getColor(6, 2), Color.pack(0xFFFFFFFF), 0f);
552         assertChannels(gainmapContents.getColor(7, 3), Color.pack(0xFFFFFFFF), 0f);
553 
554         assertChannels(gainmapContents.getColor(8, 4), Color.pack(Color.BLACK), 0f);
555         assertChannels(gainmapContents.getColor(9, 5), Color.pack(Color.BLACK), 0f);
556     }
557 
558     @Test
559     public void applyRotation180Matrix() {
560         Matrix m = new Matrix();
561         m.setRotate(180.0f, 5.f, 3.f);
562         Bitmap result = Bitmap.createBitmap(sTestImage, 0, 0, 10, 6, m, false);
563         assertEquals(result.getWidth(), 10);
564         assertEquals(result.getHeight(), 6);
565         assertTrue(result.hasGainmap());
566         Bitmap gainmapContents = result.getGainmap().getGainmapContents();
567         assertEquals(gainmapContents.getWidth(), 5);
568         assertEquals(gainmapContents.getHeight(), 3);
569         assertChannels(gainmapContents.getColor(0, 0), Color.pack(Color.BLACK), 0f);
570         assertChannels(gainmapContents.getColor(0, 1), Color.pack(Color.BLACK), 0f);
571         assertChannels(gainmapContents.getColor(1, 1), Color.pack(0xFFFFFFFF), 0f);
572         assertChannels(gainmapContents.getColor(2, 1), Color.pack(0xFF808080), 0f);
573         assertChannels(gainmapContents.getColor(3, 1), Color.pack(0xFF404040), 0f);
574         assertChannels(gainmapContents.getColor(4, 1), Color.pack(Color.BLACK), 0f);
575         assertChannels(gainmapContents.getColor(4, 2), Color.pack(Color.BLACK), 0f);
576     }
577 
578     @Test
579     public void applyRotation90Matrix() {
580         Matrix m = new Matrix();
581         m.setRotate(90.0f, 5.f, 3.f);
582         Bitmap result = Bitmap.createBitmap(sTestImage, 0, 0, 10, 6, m, false);
583         assertEquals(result.getWidth(), 6);
584         assertEquals(result.getHeight(), 10);
585         assertTrue(result.hasGainmap());
586         Bitmap gainmapContents = result.getGainmap().getGainmapContents();
587         assertEquals(gainmapContents.getWidth(), 3);
588         assertEquals(gainmapContents.getHeight(), 5);
589         assertChannels(gainmapContents.getColor(0, 0), Color.pack(Color.BLACK), 0f);
590         assertChannels(gainmapContents.getColor(1, 0), Color.pack(Color.BLACK), 0f);
591         assertChannels(gainmapContents.getColor(1, 1), Color.pack(0xFF404040), 0f);
592         assertChannels(gainmapContents.getColor(1, 2), Color.pack(0xFF808080), 0f);
593         assertChannels(gainmapContents.getColor(1, 3), Color.pack(0xFFFFFFFF), 0f);
594         assertChannels(gainmapContents.getColor(1, 4), Color.pack(Color.BLACK), 0f);
595         assertChannels(gainmapContents.getColor(2, 4), Color.pack(Color.BLACK), 0f);
596     }
597 
598     @Test
599     public void testRenderingDropsGainmap() {
600         Bitmap dest = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
601         Gainmap gainmap = new Gainmap(Bitmap.createBitmap(5, 5, Bitmap.Config.ALPHA_8));
602         dest.setGainmap(gainmap);
603         assertTrue(dest.hasGainmap());
604         Canvas canvas = new Canvas(dest);
605         assertFalse(dest.hasGainmap());
606         canvas.setBitmap(null);
607         dest.setGainmap(gainmap);
608         assertTrue(dest.hasGainmap());
609         canvas.setBitmap(dest);
610         assertFalse(dest.hasGainmap());
611     }
612 
613     @Test
614     public void testHardwareHandlingHLG() {
615         Bitmap testImage = sTestImage.copy(Bitmap.Config.HARDWARE, false);
616         assertTrue(testImage.hasGainmap());
617         assertEquals(testImage.getGainmap().getGainmapContents().getConfig(),
618                 Bitmap.Config.HARDWARE);
619         Bitmap result = renderWithHardware(BT2020_HLG, canvas -> {
620             canvas.drawBitmap(testImage, 0, 0, null);
621         });
622         assertTestImageResult(result);
623     }
624 
625     @Test
626     public void testHardwareHandlingPQ() {
627         Bitmap testImage = sTestImage.copy(Bitmap.Config.HARDWARE, false);
628         assertTrue(testImage.hasGainmap());
629         assertEquals(testImage.getGainmap().getGainmapContents().getConfig(),
630                 Bitmap.Config.HARDWARE);
631         Bitmap result = renderWithHardware(BT2020_PQ, canvas -> {
632             canvas.drawBitmap(testImage, 0, 0, null);
633         });
634         assertTestImageResult(result);
635     }
636 
637     @Test
638     public void testHardwareA8HandlingHLG() {
639         Bitmap testImage = sTestImageA8.copy(Bitmap.Config.HARDWARE, false);
640         assertTrue(testImage.hasGainmap());
641         assertEquals(testImage.getGainmap().getGainmapContents().getConfig(),
642                 Bitmap.Config.HARDWARE);
643         Bitmap result = renderWithHardware(BT2020_HLG, canvas -> {
644             canvas.drawBitmap(testImage, 0, 0, null);
645         });
646         assertTestImageResult(result);
647     }
648 
649     @Test
650     public void testHardwareA8HandlingPQ() {
651         Bitmap testImage = sTestImageA8.copy(Bitmap.Config.HARDWARE, false);
652         assertTrue(testImage.hasGainmap());
653         assertEquals(testImage.getGainmap().getGainmapContents().getConfig(),
654                 Bitmap.Config.HARDWARE);
655         Bitmap result = renderWithHardware(BT2020_PQ, canvas -> {
656             canvas.drawBitmap(testImage, 0, 0, null);
657         });
658         assertTestImageResult(result);
659     }
660 }
661