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:
parent
185741e47d
commit
89965006af
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user