Revert "Revert "Revert "Revert "Implement dynamic colors for boot animation.""""

This reverts commit ad9cf52df959489b615f30cbf072415b3352063b.

Reason for revert: Fixing broken atv test
Test: atv atp test tv/platform/simple_boot_test
Bug: 190093578

Change-Id: I9d6ecb6024ce49eef8007458b0d9bf0ff24906c7
This commit is contained in:
Shan Huang 2021-08-16 16:45:39 +00:00
parent 185741e47d
commit 89965006af
2 changed files with 137 additions and 25 deletions

View File

@ -107,9 +107,13 @@ static const char PROGRESS_PROP_NAME[] = "service.bootanim.progress";
static const char DISPLAYS_PROP_NAME[] = "persist.service.bootanim.displays";
static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1;
static constexpr size_t TEXT_POS_LEN_MAX = 16;
static const int DYNAMIC_COLOR_COUNT = 4;
static const char U_TEXTURE[] = "uTexture";
static const char U_FADE[] = "uFade";
static const char U_CROP_AREA[] = "uCropArea";
static const char U_START_COLOR_PREFIX[] = "uStartColor";
static const char U_END_COLOR_PREFIX[] = "uEndColor";
static const char U_COLOR_PROGRESS[] = "uColorProgress";
static const char A_UV[] = "aUv";
static const char A_POSITION[] = "aPosition";
static const char VERTEX_SHADER_SOURCE[] = R"(
@ -121,6 +125,28 @@ static const char VERTEX_SHADER_SOURCE[] = R"(
gl_Position = aPosition;
vUv = aUv;
})";
static const char IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE[] = R"(
precision mediump float;
uniform sampler2D uTexture;
uniform float uFade;
uniform float uColorProgress;
uniform vec4 uStartColor0;
uniform vec4 uStartColor1;
uniform vec4 uStartColor2;
uniform vec4 uStartColor3;
uniform vec4 uEndColor0;
uniform vec4 uEndColor1;
uniform vec4 uEndColor2;
uniform vec4 uEndColor3;
varying highp vec2 vUv;
void main() {
vec4 mask = texture2D(uTexture, vUv);
vec4 color = mask.r * mix(uStartColor0, uEndColor0, uColorProgress)
+ mask.g * mix(uStartColor1, uEndColor1, uColorProgress)
+ mask.b * mix(uStartColor2, uEndColor2, uColorProgress)
+ mask.a * mix(uStartColor3, uEndColor3, uColorProgress);
gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a;
})";
static const char IMAGE_FRAG_SHADER_SOURCE[] = R"(
precision mediump float;
uniform sampler2D uTexture;
@ -128,7 +154,7 @@ static const char IMAGE_FRAG_SHADER_SOURCE[] = R"(
varying highp vec2 vUv;
void main() {
vec4 color = texture2D(uTexture, vUv);
gl_FragColor = vec4(color.x, color.y, color.z, 1.0 - uFade);
gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a;
})";
static const char TEXT_FRAG_SHADER_SOURCE[] = R"(
precision mediump float;
@ -212,7 +238,8 @@ void BootAnimation::binderDied(const wp<IBinder>&) {
requestExit();
}
static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitmapInfo* outInfo) {
static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitmapInfo* outInfo,
bool premultiplyAlpha) {
AImageDecoder* decoder = nullptr;
AImageDecoder_createFromBuffer(encodedData, dataLength, &decoder);
if (!decoder) {
@ -226,6 +253,10 @@ static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitm
outInfo->stride = AImageDecoder_getMinimumStride(decoder);
outInfo->flags = 0;
if (!premultiplyAlpha) {
AImageDecoder_setUnpremultipliedRequired(decoder, true);
}
const size_t size = outInfo->stride * outInfo->height;
void* pixels = malloc(size);
int result = AImageDecoder_decodeImage(decoder, pixels, outInfo->stride, size);
@ -239,13 +270,14 @@ static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitm
}
status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
const char* name) {
const char* name, bool premultiplyAlpha) {
Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
if (asset == nullptr)
return NO_INIT;
AndroidBitmapInfo bitmapInfo;
void* pixels = decodeImage(asset->getBuffer(false), asset->getLength(), &bitmapInfo);
void* pixels = decodeImage(asset->getBuffer(false), asset->getLength(), &bitmapInfo,
premultiplyAlpha);
auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free };
asset->close();
@ -293,9 +325,11 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
return NO_ERROR;
}
status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) {
status_t BootAnimation::initTexture(FileMap* map, int* width, int* height,
bool premultiplyAlpha) {
AndroidBitmapInfo bitmapInfo;
void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo);
void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo,
premultiplyAlpha);
auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free };
// FileMap memory is never released until application exit.
@ -675,9 +709,12 @@ GLuint linkShader(GLuint vertexShader, GLuint fragmentShader) {
}
void BootAnimation::initShaders() {
bool dynamicColoringEnabled = mAnimation != nullptr && mAnimation->dynamicColoringEnabled;
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, (const GLchar *)VERTEX_SHADER_SOURCE);
GLuint imageFragmentShader =
compileShader(GL_FRAGMENT_SHADER, (const GLchar *)IMAGE_FRAG_SHADER_SOURCE);
compileShader(GL_FRAGMENT_SHADER, dynamicColoringEnabled
? (const GLchar *)IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE
: (const GLchar *)IMAGE_FRAG_SHADER_SOURCE);
GLuint textFragmentShader =
compileShader(GL_FRAGMENT_SHADER, (const GLchar *)TEXT_FRAG_SHADER_SOURCE);
@ -692,6 +729,22 @@ void BootAnimation::initShaders() {
glVertexAttribPointer(uvLocation, 2, GL_FLOAT, GL_FALSE, 0, quadUVs);
glEnableVertexAttribArray(uvLocation);
if (dynamicColoringEnabled) {
glUseProgram(mImageShader);
SLOGI("[BootAnimation] Dynamically coloring boot animation.");
for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) {
float *startColor = mAnimation->startColors[i];
float *endColor = mAnimation->endColors[i];
glUniform4f(glGetUniformLocation(mImageShader,
(U_START_COLOR_PREFIX + std::to_string(i)).c_str()),
startColor[0], startColor[1], startColor[2], 1 /* alpha */);
glUniform4f(glGetUniformLocation(mImageShader,
(U_END_COLOR_PREFIX + std::to_string(i)).c_str()),
endColor[0], endColor[1], endColor[2], 1 /* alpha */);
}
mImageColorProgressLocation = glGetUniformLocation(mImageShader, U_COLOR_PROGRESS);
}
// Initialize text shader.
mTextShader = linkShader(vertexShader, textFragmentShader);
positionLocation = glGetAttribLocation(mTextShader, A_POSITION);
@ -869,6 +922,20 @@ static bool parseColor(const char str[7], float color[3]) {
return true;
}
// Parse a color represented as a signed decimal int string.
// E.g. "-2757722" (whose hex 2's complement is 0xFFD5EBA6).
// If the input color string is empty, set color with values in defaultColor.
static void parseColorDecimalString(const std::string& colorString,
float color[3], float defaultColor[3]) {
if (colorString == "") {
memcpy(color, defaultColor, sizeof(float) * 3);
return;
}
int colorInt = atoi(colorString.c_str());
color[0] = ((float)((colorInt >> 16) & 0xFF)) / 0xFF; // r
color[1] = ((float)((colorInt >> 8) & 0xFF)) / 0xFF; // g
color[2] = ((float)(colorInt & 0xFF)) / 0xFF; // b
}
static bool readFile(ZipFileRO* zip, const char* name, String8& outString) {
ZipEntryRO entry = zip->findEntryByName(name);
@ -1010,6 +1077,8 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
return false;
}
char const* s = desString.string();
std::string dynamicColoringPartName = "";
bool postDynamicColoring = false;
// Parse the description file
for (;;) {
@ -1028,7 +1097,13 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
char color[7] = "000000"; // default to black if unspecified
char clockPos1[TEXT_POS_LEN_MAX + 1] = "";
char clockPos2[TEXT_POS_LEN_MAX + 1] = "";
char dynamicColoringPartNameBuffer[ANIM_ENTRY_NAME_MAX];
char pathType;
// start colors default to black if unspecified
char start_color_0[7] = "000000";
char start_color_1[7] = "000000";
char start_color_2[7] = "000000";
char start_color_3[7] = "000000";
int nextReadPos;
@ -1043,6 +1118,15 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
} else {
animation.progressEnabled = false;
}
} else if (sscanf(l, "dynamic_colors %" STRTO(ANIM_PATH_MAX) "s #%6s #%6s #%6s #%6s",
dynamicColoringPartNameBuffer,
start_color_0, start_color_1, start_color_2, start_color_3)) {
animation.dynamicColoringEnabled = true;
parseColor(start_color_0, animation.startColors[0]);
parseColor(start_color_1, animation.startColors[1]);
parseColor(start_color_2, animation.startColors[2]);
parseColor(start_color_3, animation.startColors[3]);
dynamicColoringPartName = std::string(dynamicColoringPartNameBuffer);
} else if (sscanf(l, "%c %d %d %" STRTO(ANIM_PATH_MAX) "s%n",
&pathType, &count, &pause, path, &nextReadPos) >= 4) {
if (pathType == 'f') {
@ -1055,6 +1139,16 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
// "clockPos1=%s, clockPos2=%s",
// pathType, count, pause, path, framesToFadeCount, color, clockPos1, clockPos2);
Animation::Part part;
if (path == dynamicColoringPartName) {
// Part is specified to use dynamic coloring.
part.useDynamicColoring = true;
part.postDynamicColoring = false;
postDynamicColoring = true;
} else {
// Part does not use dynamic coloring.
part.useDynamicColoring = false;
part.postDynamicColoring = postDynamicColoring;
}
part.playUntilComplete = pathType == 'c';
part.framesToFadeCount = framesToFadeCount;
part.count = count;
@ -1086,6 +1180,12 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
s = ++endl;
}
for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) {
parseColorDecimalString(
android::base::GetProperty("persist.bootanim.color" + std::to_string(i + 1), ""),
animation.endColors[i], animation.startColors[i]);
}
return true;
}
@ -1357,6 +1457,14 @@ bool BootAnimation::playAnimation(const Animation& animation) {
for (size_t j=0 ; j<fcount ; j++) {
if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;
// Color progress is
// - the normalized animation progress between [0, 1] for the dynamic coloring part,
// - 0 for parts that come before,
// - 1 for parts that come after.
float colorProgress = part.useDynamicColoring
? (float)j / fcount
: (part.postDynamicColoring ? 1 : 0);
processDisplayEvents();
const int animationX = (mWidth - animation.width) / 2;
@ -1371,24 +1479,14 @@ bool BootAnimation::playAnimation(const Animation& animation) {
glGenTextures(1, &frame.tid);
glBindTexture(GL_TEXTURE_2D, frame.tid);
int w, h;
initTexture(frame.map, &w, &h);
// Set decoding option to alpha unpremultiplied so that the R, G, B channels
// of transparent pixels are preserved.
initTexture(frame.map, &w, &h, false /* don't premultiply alpha */);
}
const int xc = animationX + frame.trimX;
const int yc = animationY + frame.trimY;
Region clearReg(Rect(mWidth, mHeight));
clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight));
if (!clearReg.isEmpty()) {
Region::const_iterator head(clearReg.begin());
Region::const_iterator tail(clearReg.end());
glEnable(GL_SCISSOR_TEST);
while (head != tail) {
const Rect& r2(*head++);
glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height());
glClear(GL_COLOR_BUFFER_BIT);
}
glDisable(GL_SCISSOR_TEST);
}
glClear(GL_COLOR_BUFFER_BIT);
// specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
// which is equivalent to mHeight - (yc + frame.trimHeight)
const int frameDrawY = mHeight - (yc + frame.trimHeight);
@ -1404,6 +1502,9 @@ bool BootAnimation::playAnimation(const Animation& animation) {
glUseProgram(mImageShader);
glUniform1i(mImageTextureLocation, 0);
glUniform1f(mImageFadeLocation, fade);
if (animation.dynamicColoringEnabled) {
glUniform1f(mImageColorProgressLocation, colorProgress);
}
glEnable(GL_BLEND);
drawTexturedQuad(xc, frameDrawY, frame.trimWidth, frame.trimHeight);
glDisable(GL_BLEND);

View File

@ -53,7 +53,7 @@ public:
};
struct Font {
FileMap* map;
FileMap* map = nullptr;
Texture texture;
int char_width;
int char_height;
@ -62,7 +62,7 @@ public:
struct Animation {
struct Frame {
String8 name;
FileMap* map;
FileMap* map = nullptr;
int trimX;
int trimY;
int trimWidth;
@ -90,6 +90,10 @@ public:
uint8_t* audioData;
int audioLength;
Animation* animation;
// Controls if dynamic coloring is enabled for this part.
bool useDynamicColoring = false;
// Defines if this part is played after the dynamic coloring part.
bool postDynamicColoring = false;
bool hasFadingPhase() const {
return !playUntilComplete && framesToFadeCount > 0;
@ -105,6 +109,10 @@ public:
ZipFileRO* zip;
Font clockFont;
Font progressFont;
// Controls if dynamic coloring is enabled for the whole animation.
bool dynamicColoringEnabled = false;
float startColors[4][3]; // Start colors of dynamic color transition.
float endColors[4][3]; // End colors of dynamic color transition.
};
// All callbacks will be called from this class's internal thread.
@ -163,8 +171,10 @@ private:
int displayEventCallback(int fd, int events, void* data);
void processDisplayEvents();
status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
status_t initTexture(FileMap* map, int* width, int* height);
status_t initTexture(Texture* texture, AssetManager& asset, const char* name,
bool premultiplyAlpha = true);
status_t initTexture(FileMap* map, int* width, int* height,
bool premultiplyAlpha = true);
status_t initFont(Font* font, const char* fallback);
void initShaders();
bool android();
@ -226,6 +236,7 @@ private:
GLuint mImageTextureLocation;
GLuint mTextCropAreaLocation;
GLuint mTextTextureLocation;
GLuint mImageColorProgressLocation;
};
// ---------------------------------------------------------------------------