• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // BootAnimationTest.cpp: Tests that make the same gl calls as Android's boot animations
8 
9 #include "test_utils/ANGLETest.h"
10 #include "test_utils/gl_raii.h"
11 
12 #include "common/debug.h"
13 #include "util/test_utils.h"
14 
15 using namespace angle;
16 
17 // Makes the same GLES 1 calls as Android's default boot animation
18 // The original animation uses 2 different images -
19 // One image acts as a mask and one that moves(a gradient that acts as a shining light)
20 // We do the same here except with different images of much smaller resolution
21 // The results of each frame of the animation are compared against expected values
22 // The original source of the boot animation can be found here:
23 // https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/cmds/bootanimation/BootAnimation.cpp#422
24 class BootAnimationTest : public ANGLETest<>
25 {
26   protected:
BootAnimationTest()27     BootAnimationTest()
28     {
29         setWindowWidth(kWindowWidth);
30         setWindowHeight(kWindowHeight);
31         setConfigRedBits(8);
32         setConfigGreenBits(8);
33         setConfigBlueBits(8);
34         setConfigAlphaBits(8);
35     }
36 
initTextureWithData(GLuint * texture,const void * data,GLint width,GLint height,unsigned int channels)37     void initTextureWithData(GLuint *texture,
38                              const void *data,
39                              GLint width,
40                              GLint height,
41                              unsigned int channels)
42     {
43         GLint crop[4] = {0, height, width, -height};
44 
45         glGenTextures(1, texture);
46         glBindTexture(GL_TEXTURE_2D, *texture);
47 
48         switch (channels)
49         {
50             case 3:
51                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB,
52                              GL_UNSIGNED_SHORT_5_6_5, data);
53                 break;
54             case 4:
55                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
56                              data);
57                 break;
58             default:
59                 UNREACHABLE();
60         }
61 
62         glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
63         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
64         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
65         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
66         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
67     }
68 
testSetUp()69     void testSetUp() override
70     {
71         EGLWindow *window = getEGLWindow();
72         mDisplay          = window->getDisplay();
73         mSurface          = window->getSurface();
74 
75         /**
76          * The mask is a 4 by 1 texture colored:
77          * --- --- --- ---
78          * |B| |A| |B| |A|
79          * --- --- --- ---
80          * B is black, A is black with alpha of 0xFF
81          */
82         constexpr GLubyte kMask[] = {
83             0x0, 0x0, 0x0, 0xff,  // black
84             0x0, 0x0, 0x0, 0x0,   // transparent black
85             0x0, 0x0, 0x0, 0xff,  // black
86             0x0, 0x0, 0x0, 0x0    // transparent black
87         };
88         /**
89          * The shine is a 8 by 1 texture colored:
90          * --- --- --- --- --- --- --- ---
91          * |R| |R| |G| |G| |B| |B| |W| |W|
92          * --- --- --- --- --- --- --- ---
93          * R is red, G is green, B is blue, W is white
94          */
95         constexpr GLushort kShine[] = {0xF800,  // 2 red pixels
96                                        0xF800,
97                                        0x07E0,  // 2 green pixels
98                                        0x07E0,
99                                        0x001F,  // 2 blue pixels
100                                        0x001F,
101                                        0xFFFF,  // 2 white pixels
102                                        0xFFFF};
103 
104         constexpr unsigned int kMaskColorChannels  = 4;
105         constexpr unsigned int kShineColorChannels = 3;
106 
107         initTextureWithData(&mTextureNames[0], kMask, kMaskWidth, kMaskHeight, kMaskColorChannels);
108         initTextureWithData(&mTextureNames[1], kShine, kShineWidth, kShineHeight,
109                             kShineColorChannels);
110 
111         // clear screen
112         glShadeModel(GL_FLAT);
113         glDisable(GL_DITHER);
114         glDisable(GL_SCISSOR_TEST);
115         glClearColor(0, 1, 1, 1);
116         glClear(GL_COLOR_BUFFER_BIT);
117         eglSwapBuffers(mDisplay, mSurface);
118         glEnable(GL_TEXTURE_2D);
119         glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
120 
121         glScissor(kMaskBoundaryLeft, kMaskBoundaryBottom, kMaskWidth, kMaskHeight);
122 
123         // Blend state
124         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
125         glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
126     }
127 
testTearDown()128     void testTearDown() override
129     {
130         glDeleteTextures(1, &mTextureNames[0]);
131         glDeleteTextures(1, &mTextureNames[1]);
132     }
133 
checkMaskColor(unsigned int iterationCount,unsigned int maskSlot)134     void checkMaskColor(unsigned int iterationCount, unsigned int maskSlot)
135     {
136         // kOffset is necessary as the visible part is the left most section of the shine
137         // but then we shift the images right
138         constexpr unsigned int kOffset = 7;
139 
140         // this solves for the color at any given position in our shine equivalent
141         constexpr unsigned int kPossibleColors = 4;
142         constexpr unsigned int kColorsInARow   = 2;
143         unsigned int color =
144             ((iterationCount - maskSlot + kOffset) / kColorsInARow) % kPossibleColors;
145         switch (color)
146         {
147             case 0:  // white
148                 EXPECT_PIXEL_EQ(kMaskBoundaryLeft + maskSlot, kMaskBoundaryBottom, 0xFF, 0xFF, 0xFF,
149                                 0xFF);
150                 break;
151             case 1:  // blue
152                 EXPECT_PIXEL_EQ(kMaskBoundaryLeft + maskSlot, kMaskBoundaryBottom, 0x00, 0x00, 0xFF,
153                                 0xFF);
154                 break;
155             case 2:  // green
156                 EXPECT_PIXEL_EQ(kMaskBoundaryLeft + maskSlot, kMaskBoundaryBottom, 0x00, 0xFF, 0x00,
157                                 0xFF);
158                 break;
159             case 3:  // red
160                 EXPECT_PIXEL_EQ(kMaskBoundaryLeft + maskSlot, kMaskBoundaryBottom, 0xFF, 0x00, 0x00,
161                                 0xFF);
162                 break;
163             default:
164                 UNREACHABLE();
165         }
166     }
167 
checkClearColor()168     void checkClearColor()
169     {
170         // Areas outside of the 4x1 mask area should be the clear color due to our glScissor call
171         constexpr unsigned int kImageHeight = 1;
172         EXPECT_PIXEL_RECT_EQ(0, 0, kWindowWidth, kMaskBoundaryBottom, GLColor::cyan);
173         EXPECT_PIXEL_RECT_EQ(0, kMaskBoundaryBottom + kImageHeight, kWindowWidth,
174                              (kWindowHeight - (kMaskBoundaryBottom + kImageHeight)), GLColor::cyan);
175         EXPECT_PIXEL_RECT_EQ(0, kMaskBoundaryBottom, kMaskBoundaryLeft, kImageHeight,
176                              GLColor::cyan);
177         EXPECT_PIXEL_RECT_EQ(kMaskBoundaryLeft + kMaskWidth, kMaskBoundaryBottom,
178                              (kWindowWidth - (kMaskBoundaryLeft + kMaskWidth)), kImageHeight,
179                              GLColor::cyan);
180     }
181 
validateColors(unsigned int iterationCount)182     void validateColors(unsigned int iterationCount)
183     {
184         // validate all slots in our mask
185         for (unsigned int maskSlot = 0; maskSlot < kMaskWidth; ++maskSlot)
186         {
187             // parts that are blocked in our mask are black
188             switch (maskSlot)
189             {
190                 case kBlackMask[0]:
191                 case kBlackMask[1]:
192                     // slots with non zero alpha are black
193                     EXPECT_PIXEL_EQ(kMaskBoundaryLeft + maskSlot, kMaskBoundaryBottom, 0x00, 0x00,
194                                     0x00, 0xFF);
195                     continue;
196                 default:
197                     checkMaskColor(iterationCount, maskSlot);
198             }
199         }
200         // validate surrounding pixels are equal to clear color
201         checkClearColor();
202     }
203 
204     EGLDisplay mDisplay = EGL_NO_DISPLAY;
205     EGLSurface mSurface = EGL_NO_SURFACE;
206     GLuint mTextureNames[2];
207     // This creates a kWindowWidth x kWindowHeight window.
208     // A kMaskWidth by kMaskHeight rectangle is lit up by the shine
209     // This lit up rectangle is positioned at (kMaskBoundaryLeft, kMaskBoundaryBottom)
210     // The border around the area is cleared to GLColor::cyan
211     static constexpr GLint kMaskBoundaryLeft    = 15;
212     static constexpr GLint kMaskBoundaryBottom  = 7;
213     static constexpr unsigned int kMaskWidth    = 4;
214     static constexpr unsigned int kMaskHeight   = 1;
215     static constexpr unsigned int kShineWidth   = 8;
216     static constexpr unsigned int kShineHeight  = 1;
217     static constexpr unsigned int kWindowHeight = 16;
218     static constexpr unsigned int kWindowWidth  = 32;
219     static constexpr unsigned int kBlackMask[2] = {0, 2};
220 };
221 
TEST_P(BootAnimationTest,DefaultBootAnimation)222 TEST_P(BootAnimationTest, DefaultBootAnimation)
223 {
224     // http://anglebug.com/5085
225     ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsVulkan());
226 
227     constexpr uint64_t kMaxIterationCount = 8;  // number of times we shift the shine textures
228     constexpr int kStartingShinePosition  = kMaskBoundaryLeft - kShineWidth;
229     constexpr int kEndingShinePosition    = kMaskBoundaryLeft;
230     GLint x                               = kStartingShinePosition;
231     uint64_t iterationCount               = 0;
232     do
233     {
234         glDisable(GL_SCISSOR_TEST);
235         glClear(GL_COLOR_BUFFER_BIT);
236         glEnable(GL_SCISSOR_TEST);
237         glDisable(GL_BLEND);
238         glBindTexture(GL_TEXTURE_2D, mTextureNames[1]);
239         glDrawTexiOES(x, kMaskBoundaryBottom, 0, kShineWidth, kShineHeight);
240         glDrawTexiOES(x + kShineWidth, kMaskBoundaryBottom, 0, kShineWidth, kShineHeight);
241         glEnable(GL_BLEND);
242         glBindTexture(GL_TEXTURE_2D, mTextureNames[0]);
243         glDrawTexiOES(kMaskBoundaryLeft, kMaskBoundaryBottom, 0, kMaskWidth, kMaskHeight);
244         validateColors(iterationCount);
245         EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
246         if (res == EGL_FALSE)
247         {
248             break;
249         }
250 
251         if (x == kEndingShinePosition)
252         {
253             x = kStartingShinePosition;
254         }
255         ++x;
256         ++iterationCount;
257     } while (iterationCount < kMaxIterationCount);
258 }
259 
260 ANGLE_INSTANTIATE_TEST_ES1(BootAnimationTest);