summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/androidfw/Asset.cpp18
-rw-r--r--libs/androidfw/BackupData.cpp2
-rw-r--r--libs/androidfw/BackupHelpers.cpp6
-rw-r--r--libs/androidfw/CursorWindow.cpp16
-rw-r--r--libs/androidfw/ResourceTypes.cpp150
-rw-r--r--libs/androidfw/ZipUtils.cpp4
-rw-r--r--libs/hwui/Android.mk1
-rw-r--r--libs/hwui/DeferredLayerUpdater.h2
-rw-r--r--libs/hwui/DisplayList.cpp537
-rw-r--r--libs/hwui/DisplayList.h130
-rw-r--r--libs/hwui/DisplayListRenderer.cpp4
-rw-r--r--libs/hwui/DisplayListRenderer.h2
-rw-r--r--libs/hwui/Layer.cpp4
-rw-r--r--libs/hwui/RenderNode.cpp571
-rw-r--r--libs/hwui/RenderNode.h200
-rw-r--r--libs/hwui/SpotShadow.cpp7
16 files changed, 877 insertions, 777 deletions
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
index ce6cc38b8357..589211fa60b8 100644
--- a/libs/androidfw/Asset.cpp
+++ b/libs/androidfw/Asset.cpp
@@ -72,7 +72,7 @@ String8 Asset::getAssetAllocations()
}
cur = cur->mNext;
}
-
+
return res;
}
@@ -84,18 +84,18 @@ Asset::Asset(void)
mNext = mPrev = NULL;
if (gTail == NULL) {
gHead = gTail = this;
- } else {
- mPrev = gTail;
- gTail->mNext = this;
- gTail = this;
- }
+ } else {
+ mPrev = gTail;
+ gTail->mNext = this;
+ gTail = this;
+ }
//ALOGI("Creating Asset %p #%d\n", this, gCount);
}
Asset::~Asset(void)
{
AutoMutex _l(gAssetLock);
- gCount--;
+ gCount--;
if (gHead == this) {
gHead = mNext;
}
@@ -409,7 +409,7 @@ status_t _FileAsset::openChunk(const char* fileName, int fd, off64_t offset, siz
}
mFileName = fileName != NULL ? strdup(fileName) : NULL;
-
+
return NO_ERROR;
}
@@ -538,7 +538,7 @@ void _FileAsset::close(void)
free(mFileName);
mFileName = NULL;
}
-
+
if (mFp != NULL) {
// can only be NULL when called from destructor
// (otherwise we would never return this object)
diff --git a/libs/androidfw/BackupData.cpp b/libs/androidfw/BackupData.cpp
index 1a5c55ce8eda..a5b94167fdfc 100644
--- a/libs/androidfw/BackupData.cpp
+++ b/libs/androidfw/BackupData.cpp
@@ -291,7 +291,7 @@ BackupDataReader::ReadNextHeader(bool* done, int* type)
(int)(m_pos - sizeof(m_header)), (int)m_header.type);
m_status = EINVAL;
}
-
+
return m_status;
}
diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp
index 302fbf63af52..ab837ad71cbf 100644
--- a/libs/androidfw/BackupHelpers.cpp
+++ b/libs/androidfw/BackupHelpers.cpp
@@ -568,8 +568,8 @@ int write_tarfile(const String8& packageName, const String8& domain,
// [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
// [ 116 : 8 ] gid -- ignored in Android format
- snprintf(buf + 108, 8, "0%lo", s.st_uid);
- snprintf(buf + 116, 8, "0%lo", s.st_gid);
+ snprintf(buf + 108, 8, "0%lo", (unsigned long)s.st_uid);
+ snprintf(buf + 116, 8, "0%lo", (unsigned long)s.st_gid);
// [ 124 : 12 ] file size in bytes
if (s.st_size > 077777777777LL) {
@@ -778,7 +778,7 @@ RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
ALOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
return errno;
}
-
+
while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
err = write(fd, buf, amt);
if (err != amt) {
diff --git a/libs/androidfw/CursorWindow.cpp b/libs/androidfw/CursorWindow.cpp
index 0f54edb6f915..2b74a3308381 100644
--- a/libs/androidfw/CursorWindow.cpp
+++ b/libs/androidfw/CursorWindow.cpp
@@ -1,16 +1,16 @@
/*
* Copyright (C) 2006-2007 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
*/
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 98849e359825..652cd4a142f7 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -1266,7 +1266,7 @@ ResXMLParser::event_code_t ResXMLParser::nextNode()
const ResXMLTree_node* next = (const ResXMLTree_node*)
(((const uint8_t*)mCurNode) + dtohl(mCurNode->header.size));
//ALOGW("Next node: prev=%p, next=%p\n", mCurNode, next);
-
+
if (((const uint8_t*)next) >= mTree.mDataEnd) {
mCurNode = NULL;
return (mEventCode=END_DOCUMENT);
@@ -1303,7 +1303,7 @@ ResXMLParser::event_code_t ResXMLParser::nextNode()
(int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)));
continue;
}
-
+
if ((totalSize-headerSize) < minExtSize) {
ALOGW("Bad XML block: header type 0x%x in node at 0x%x has size %d, need %d\n",
(int)dtohs(next->header.type),
@@ -1311,10 +1311,10 @@ ResXMLParser::event_code_t ResXMLParser::nextNode()
(int)(totalSize-headerSize), (int)minExtSize);
return (mEventCode=BAD_DOCUMENT);
}
-
+
//printf("CurNode=%p, CurExt=%p, headerSize=%d, minExtSize=%d\n",
// mCurNode, mCurExt, headerSize, minExtSize);
-
+
return eventCode;
} while (true);
}
@@ -2717,7 +2717,7 @@ struct ResTable::Package
delete types[i];
}
}
-
+
ResTable* const owner;
const Header* const header;
const ResTable_package* const package;
@@ -2725,7 +2725,7 @@ struct ResTable::Package
ResStringPool typeStrings;
ResStringPool keyStrings;
-
+
const Type* getType(size_t idx) const {
return idx < types.size() ? types[idx] : NULL;
}
@@ -2775,18 +2775,18 @@ struct ResTable::PackageGroup
bags = NULL;
}
}
-
+
ResTable* const owner;
String16 const name;
uint32_t const id;
Vector<Package*> packages;
-
+
// This is for finding typeStrings and other common package stuff.
Package* basePackage;
// For quick access.
size_t typeCount;
-
+
// Computed attribute bags, first indexed by the type and second
// by the entry in that type.
bag_set*** bags;
@@ -2935,7 +2935,7 @@ status_t ResTable::Theme::applyStyle(uint32_t resID, bool force)
//ALOGI("Applying style 0x%08x (force=%d) theme %p...\n", resID, force, this);
//dumpToLog();
-
+
return NO_ERROR;
}
@@ -2944,7 +2944,7 @@ status_t ResTable::Theme::setTo(const Theme& other)
//ALOGI("Setting theme %p from theme %p...\n", this, &other);
//dumpToLog();
//other.dumpToLog();
-
+
if (&mTable == &other.mTable) {
for (size_t i=0; i<Res_MAXPACKAGE; i++) {
if (mPackages[i] != NULL) {
@@ -2974,7 +2974,7 @@ status_t ResTable::Theme::setTo(const Theme& other)
//ALOGI("Final theme:");
//dumpToLog();
-
+
return NO_ERROR;
}
@@ -2984,7 +2984,7 @@ ssize_t ResTable::Theme::getAttribute(uint32_t resID, Res_value* outValue,
int cnt = 20;
if (outTypeSpecFlags != NULL) *outTypeSpecFlags = 0;
-
+
do {
const ssize_t p = mTable.getResourcePackageIndex(resID);
const uint32_t t = Res_GETTYPE(resID);
@@ -3058,12 +3058,12 @@ void ResTable::Theme::dumpToLog() const
for (size_t i=0; i<Res_MAXPACKAGE; i++) {
package_info* pi = mPackages[i];
if (pi == NULL) continue;
-
+
ALOGI(" Package #0x%02x:\n", (int)(i+1));
for (size_t j=0; j<pi->numTypes; j++) {
type_info& ti = pi->types[j];
if (ti.numEntries == 0) continue;
-
+
ALOGI(" Type #0x%02x:\n", (int)(j+1));
for (size_t k=0; k<ti.numEntries; k++) {
theme_entry& te = ti.entries[k];
@@ -3125,11 +3125,11 @@ status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData, const
status_t ResTable::add(ResTable* src)
{
mError = src->mError;
-
+
for (size_t i=0; i<src->mHeaders.size(); i++) {
mHeaders.add(src->mHeaders[i]);
}
-
+
for (size_t i=0; i<src->mPackageGroups.size(); i++) {
PackageGroup* srcPg = src->mPackageGroups[i];
PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id);
@@ -3140,14 +3140,14 @@ status_t ResTable::add(ResTable* src)
pg->typeCount = srcPg->typeCount;
mPackageGroups.add(pg);
}
-
+
memcpy(mPackageMap, src->mPackageMap, sizeof(mPackageMap));
-
+
return mError;
}
status_t ResTable::addInternal(const void* data, size_t size, const int32_t cookie,
- Asset* asset, bool copyData, const Asset* idmap)
+ Asset* /*asset*/, bool copyData, const Asset* idmap)
{
if (!data) return NO_ERROR;
Header* header = new Header(this);
@@ -3171,7 +3171,7 @@ status_t ResTable::addInternal(const void* data, size_t size, const int32_t cook
LOAD_TABLE_NOISY(
ALOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%d, asset=%p, copy=%d "
"idmap=%p\n", data, size, cookie, asset, copyData, idmap));
-
+
if (copyData || notDeviceEndian) {
header->ownedData = malloc(size);
if (header->ownedData == NULL) {
@@ -3503,7 +3503,7 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag
// are identical (diff == 0), or overlay packages will not take effect.
continue;
}
-
+
bestItem = thisConfig;
bestValue = item;
bestPackage = package;
@@ -3573,7 +3573,7 @@ ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex,
const char16_t* ResTable::valueToString(
const Res_value* value, size_t stringBlock,
- char16_t tmpBuffer[TMP_BUFFER_SIZE], size_t* outLen)
+ char16_t /*tmpBuffer*/ [TMP_BUFFER_SIZE], size_t* outLen)
{
if (!value) {
return NULL;
@@ -3596,7 +3596,7 @@ ssize_t ResTable::lockBag(uint32_t resID, const bag_entry** outBag) const
return err;
}
-void ResTable::unlockBag(const bag_entry* bag) const
+void ResTable::unlockBag(const bag_entry* /*bag*/) const
{
//printf("<<< unlockBag %p\n", this);
mLock.unlock();
@@ -3697,7 +3697,7 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
bag_set* set = NULL;
TABLE_NOISY(ALOGI("Building bag: %p\n", (void*)resID));
-
+
ResTable_config bestConfig;
memset(&bestConfig, 0, sizeof(bestConfig));
@@ -3763,7 +3763,7 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
? dtohl(((const ResTable_map_entry*)entry)->parent.ident) : 0;
const uint32_t count = entrySize >= sizeof(ResTable_map_entry)
? dtohl(((const ResTable_map_entry*)entry)->count) : 0;
-
+
size_t N = count;
TABLE_NOISY(ALOGI("Found map: size=%p parent=%p count=%d\n",
@@ -3807,7 +3807,7 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
} else {
set->typeSpecFlags = -1;
}
-
+
// Now merge in the new attributes...
ssize_t curOff = offset;
const ResTable_map* map;
@@ -4070,7 +4070,7 @@ nope:
TABLE_NOISY(printf("Expected type structure not found in package %s for idnex %d\n",
String8(group->name).string(), ti));
}
-
+
size_t NTC = typeConfigs->configs.size();
for (size_t tci=0; tci<NTC; tci++) {
const ResTable_type* const ty = typeConfigs->configs[tci];
@@ -4086,9 +4086,9 @@ nope:
if (offset == ResTable_type::NO_ENTRY) {
continue;
}
-
+
offset += typeOffset;
-
+
if (offset > (dtohl(ty->header.size)-sizeof(ResTable_entry))) {
ALOGW("ResTable_entry at %d is beyond type chunk data %d",
offset, dtohl(ty->header.size));
@@ -4102,7 +4102,7 @@ nope:
String8(name, nameLen).string());
return 0;
}
-
+
const ResTable_entry* const entry = (const ResTable_entry*)
(((const uint8_t*)ty) + offset);
if (dtohs(entry->size) < sizeof(*entry)) {
@@ -4259,7 +4259,7 @@ static bool parse_unit(const char* str, Res_value* outValue,
if (*realEnd != 0) {
return false;
}
-
+
const unit_entry* cur = unitNames;
while (cur->name) {
if (len == cur->len && strncmp(cur->name, str, len) == 0) {
@@ -4410,7 +4410,7 @@ bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
if (neg) {
mantissa = (-mantissa) & Res_value::COMPLEX_MANTISSA_MASK;
}
- outValue->data |=
+ outValue->data |=
(radix<<Res_value::COMPLEX_RADIX_SHIFT)
| (mantissa<<Res_value::COMPLEX_MANTISSA_SHIFT);
//printf("Input value: %f 0x%016Lx, mult: %f, radix: %d, shift: %d, final: 0x%08x\n",
@@ -4523,7 +4523,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
// Note: we don't check attrType here because the reference can
// be to any other type; we just need to count on the client making
// sure the referenced type is correct.
-
+
//printf("Looking up ref: %s\n", String8(s, len).string());
// It's a reference!
@@ -4610,7 +4610,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
}
}
}
-
+
if (*s == '#') {
// It's a color! Convert to an integer of the form 0xaarrggbb.
uint32_t color = 0;
@@ -4710,7 +4710,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
// String8(package).string(), String8(type).string(),
// String8(name).string());
uint32_t specFlags = 0;
- uint32_t rid =
+ uint32_t rid =
identifierForName(name.string(), name.size(),
type.string(), type.size(),
package.string(), package.size(), &specFlags);
@@ -4875,7 +4875,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
return true;
}
}
-
+
}
bag++;
cnt--;
@@ -5240,43 +5240,43 @@ ssize_t ResTable::getEntry(
entryIndex, (int)allTypes->entryCount);
return BAD_TYPE;
}
-
+
const ResTable_type* type = NULL;
uint32_t offset = ResTable_type::NO_ENTRY;
ResTable_config bestConfig;
memset(&bestConfig, 0, sizeof(bestConfig)); // make the compiler shut up
-
+
const size_t NT = allTypes->configs.size();
for (size_t i=0; i<NT; i++) {
const ResTable_type* const thisType = allTypes->configs[i];
if (thisType == NULL) continue;
-
+
ResTable_config thisConfig;
thisConfig.copyFromDtoH(thisType->config);
TABLE_GETENTRY(ALOGI("Match entry 0x%x in type 0x%x (sz 0x%x): %s\n",
entryIndex, typeIndex+1, dtohl(thisType->config.size),
thisConfig.toString().string()));
-
+
// Check to make sure this one is valid for the current parameters.
if (config && !thisConfig.match(*config)) {
TABLE_GETENTRY(ALOGI("Does not match config!\n"));
continue;
}
-
+
// Check if there is the desired entry in this type.
-
+
const uint8_t* const end = ((const uint8_t*)thisType)
+ dtohl(thisType->header.size);
const uint32_t* const eindex = (const uint32_t*)
(((const uint8_t*)thisType) + dtohs(thisType->header.headerSize));
-
+
uint32_t thisOffset = dtohl(eindex[entryIndex]);
if (thisOffset == ResTable_type::NO_ENTRY) {
TABLE_GETENTRY(ALOGI("Skipping because it is not defined!\n"));
continue;
}
-
+
if (type != NULL) {
// Check if this one is less specific than the last found. If so,
// we will skip it. We check starting with things we most care
@@ -5286,19 +5286,19 @@ ssize_t ResTable::getEntry(
continue;
}
}
-
+
type = thisType;
offset = thisOffset;
bestConfig = thisConfig;
TABLE_GETENTRY(ALOGI("Best entry so far -- using it!\n"));
if (!config) break;
}
-
+
if (type == NULL) {
TABLE_GETENTRY(ALOGI("No value found for requested entry!\n"));
return BAD_INDEX;
}
-
+
offset += dtohl(type->entriesStart);
TABLE_NOISY(aout << "Looking in resource table " << package->header->header
<< ", typeOff="
@@ -5363,7 +5363,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
dtohl(pkg->keyStrings));
return (mError=BAD_TYPE);
}
-
+
Package* package = NULL;
PackageGroup* group = NULL;
uint32_t id = idmap_id != 0 ? idmap_id : dtohl(pkg->id);
@@ -5372,12 +5372,12 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
// always loaded alongside their idmaps, but during idmap creation
// the package is temporarily loaded by itself.
if (id < 256) {
-
+
package = new Package(this, header, pkg);
if (package == NULL) {
return (mError=NO_MEMORY);
}
-
+
size_t idx = mPackageMap[id];
if (idx == 0) {
idx = mPackageGroups.size()+1;
@@ -5411,7 +5411,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
return (mError=err);
}
group->basePackage = package;
-
+
mPackageMap[id] = (uint8_t)idx;
} else {
group = mPackageGroups.itemAt(idx-1);
@@ -5428,10 +5428,10 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
return NO_ERROR;
}
-
+
// Iterate through all chunks.
size_t curPackage = 0;
-
+
const ResChunk_header* chunk =
(const ResChunk_header*)(((const uint8_t*)pkg)
+ dtohs(pkg->header.headerSize));
@@ -5450,9 +5450,9 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
if (err != NO_ERROR) {
return (mError=err);
}
-
+
const size_t typeSpecSize = dtohl(typeSpec->header.size);
-
+
LOAD_TABLE_NOISY(printf("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n",
(void*)(base-(const uint8_t*)chunk),
dtohs(typeSpec->header.type),
@@ -5468,12 +5468,12 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
(void*)typeSpecSize);
return (mError=BAD_TYPE);
}
-
+
if (typeSpec->id == 0) {
ALOGW("ResTable_type has an id of 0.");
return (mError=BAD_TYPE);
}
-
+
while (package->types.size() < typeSpec->id) {
package->types.add(NULL);
}
@@ -5489,7 +5489,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
t->typeSpecFlags = (const uint32_t*)(
((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
t->typeSpec = typeSpec;
-
+
} else if (ctype == RES_TABLE_TYPE_TYPE) {
const ResTable_type* type = (const ResTable_type*)(chunk);
err = validate_chunk(&type->header, sizeof(*type)-sizeof(ResTable_config)+4,
@@ -5497,9 +5497,9 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
if (err != NO_ERROR) {
return (mError=err);
}
-
+
const uint32_t typeSize = dtohl(type->header.size);
-
+
LOAD_TABLE_NOISY(printf("Type off %p: type=0x%x, headerSize=0x%x, size=%p\n",
(void*)(base-(const uint8_t*)chunk),
dtohs(type->header.type),
@@ -5523,7 +5523,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
ALOGW("ResTable_type has an id of 0.");
return (mError=BAD_TYPE);
}
-
+
while (package->types.size() < type->id) {
package->types.add(NULL);
}
@@ -5536,7 +5536,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
(int)dtohl(type->entryCount), (int)t->entryCount);
return (mError=BAD_TYPE);
}
-
+
TABLE_GETENTRY(
ResTable_config thisConfig;
thisConfig.copyFromDtoH(type->config);
@@ -5557,7 +5557,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
if (group->typeCount == 0) {
group->typeCount = package->types.size();
}
-
+
return NO_ERROR;
}
@@ -5757,7 +5757,7 @@ static void print_complex(uint32_t complex, bool isFraction)
* RADIX_MULTS[(complex>>Res_value::COMPLEX_RADIX_SHIFT)
& Res_value::COMPLEX_RADIX_MASK];
printf("%f", value);
-
+
if (!isFraction) {
switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
case Res_value::COMPLEX_UNIT_PX: printf("px"); break;
@@ -5832,7 +5832,7 @@ void ResTable::print_value(const Package* pkg, const Res_value& value) const
} else {
printf("(string) null\n");
}
- }
+ }
} else if (value.dataType == Res_value::TYPE_FLOAT) {
printf("(float) %g\n", *(const float*)&value.data);
} else if (value.dataType == Res_value::TYPE_DIMENSION) {
@@ -5875,7 +5875,7 @@ void ResTable::print(bool inclValues) const
printf("Package Group %d id=%d packageCount=%d name=%s\n",
(int)pgIndex, pg->id, (int)pg->packages.size(),
String8(pg->name).string());
-
+
size_t pkgCount = pg->packages.size();
for (size_t pkgIndex=0; pkgIndex<pkgCount; pkgIndex++) {
const Package* pkg = pg->packages[pkgIndex];
@@ -5942,17 +5942,17 @@ void ResTable::print(bool inclValues) const
continue;
}
for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) {
-
+
const uint8_t* const end = ((const uint8_t*)type)
+ dtohl(type->header.size);
const uint32_t* const eindex = (const uint32_t*)
(((const uint8_t*)type) + dtohs(type->header.headerSize));
-
+
uint32_t thisOffset = dtohl(eindex[entryIndex]);
if (thisOffset == ResTable_type::NO_ENTRY) {
continue;
}
-
+
uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
| (0x00ff0000 & ((typeIndex+1)<<16))
| (0x0000ffff & (entryIndex));
@@ -5985,7 +5985,7 @@ void ResTable::print(bool inclValues) const
entriesStart, thisOffset, typeSize);
continue;
}
-
+
const ResTable_entry* ent = (const ResTable_entry*)
(((const uint8_t*)type) + entriesStart + thisOffset);
if (((entriesStart + thisOffset)&0x3) != 0) {
@@ -5993,7 +5993,7 @@ void ResTable::print(bool inclValues) const
(entriesStart + thisOffset));
continue;
}
-
+
uintptr_t esize = dtohs(ent->size);
if ((esize&0x3) != 0) {
printf("NON-INTEGER ResTable_entry SIZE: 0x%x\n", esize);
@@ -6004,7 +6004,7 @@ void ResTable::print(bool inclValues) const
entriesStart, thisOffset, esize, typeSize);
continue;
}
-
+
const Res_value* valuePtr = NULL;
const ResTable_map_entry* bagPtr = NULL;
Res_value value;
@@ -6019,12 +6019,12 @@ void ResTable::print(bool inclValues) const
(int)value.dataType, (int)value.data,
(int)value.size, (int)value.res0);
}
-
+
if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) {
printf(" (PUBLIC)");
}
printf("\n");
-
+
if (inclValues) {
if (valuePtr != NULL) {
printf(" ");
diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp
index e9ac2fe25f58..6fa0f14ecb8e 100644
--- a/libs/androidfw/ZipUtils.cpp
+++ b/libs/androidfw/ZipUtils.cpp
@@ -127,7 +127,7 @@ static const unsigned long kReadBufSize = 32768;
goto z_bail;
}
- /* output buffer holds all, so no need to write the output */
+ /* output buffer holds all, so no need to write the output */
} while (zerr == Z_OK);
assert(zerr == Z_STREAM_END); /* other errors should've been caught */
@@ -197,7 +197,7 @@ public:
{
}
- long read(unsigned char** nextBuffer, long readSize) {
+ long read(unsigned char** nextBuffer, long /*readSize*/) {
if (!mBufferReturned) {
mBufferReturned = true;
*nextBuffer = mInput;
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index eeff4c0949a0..4de755d6084c 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -38,6 +38,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
Program.cpp \
ProgramCache.cpp \
RenderBufferCache.cpp \
+ RenderNode.cpp \
RenderProperties.cpp \
ResourceCache.cpp \
ShadowTessellator.cpp \
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index d124cdea2454..cf745eed1ee6 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -22,10 +22,10 @@
#include <SkMatrix.h>
#include <utils/StrongPointer.h>
-#include "DisplayList.h"
#include "Layer.h"
#include "OpenGLRenderer.h"
#include "Rect.h"
+#include "RenderNode.h"
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index f4de8ec1cc0d..9e6a96d38713 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -29,543 +29,6 @@
namespace android {
namespace uirenderer {
-void RenderNode::outputLogBuffer(int fd) {
- DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
- if (logBuffer.isEmpty()) {
- return;
- }
-
- FILE *file = fdopen(fd, "a");
-
- fprintf(file, "\nRecent DisplayList operations\n");
- logBuffer.outputCommands(file);
-
- String8 cachesLog;
- Caches::getInstance().dumpMemoryUsage(cachesLog);
- fprintf(file, "\nCaches:\n%s", cachesLog.string());
- fprintf(file, "\n");
-
- fflush(file);
-}
-
-RenderNode::RenderNode() : mDestroyed(false), mDisplayListData(0) {
-}
-
-RenderNode::~RenderNode() {
- LOG_ALWAYS_FATAL_IF(mDestroyed, "Double destroyed DisplayList %p", this);
-
- mDestroyed = true;
- delete mDisplayListData;
-}
-
-void RenderNode::destroyDisplayListDeferred(RenderNode* displayList) {
- if (displayList) {
- DISPLAY_LIST_LOGD("Deferring display list destruction");
- Caches::getInstance().deleteDisplayListDeferred(displayList);
- }
-}
-
-void RenderNode::setData(DisplayListData* data) {
- delete mDisplayListData;
- mDisplayListData = data;
- if (mDisplayListData) {
- Caches::getInstance().registerFunctors(mDisplayListData->functorCount);
- }
-}
-
-/**
- * This function is a simplified version of replay(), where we simply retrieve and log the
- * display list. This function should remain in sync with the replay() function.
- */
-void RenderNode::output(uint32_t level) {
- ALOGD("%*sStart display list (%p, %s, render=%d)", (level - 1) * 2, "", this,
- mName.string(), isRenderable());
- ALOGD("%*s%s %d", level * 2, "", "Save",
- SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-
- outputViewProperties(level);
- int flags = DisplayListOp::kOpLogFlag_Recurse;
- for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
- mDisplayListData->displayListOps[i]->output(level, flags);
- }
-
- ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string());
-}
-
-void RenderNode::outputViewProperties(const int level) {
- properties().updateMatrix();
- if (properties().mLeft != 0 || properties().mTop != 0) {
- ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", properties().mLeft, properties().mTop);
- }
- if (properties().mStaticMatrix) {
- ALOGD("%*sConcatMatrix (static) %p: " SK_MATRIX_STRING,
- level * 2, "", properties().mStaticMatrix, SK_MATRIX_ARGS(properties().mStaticMatrix));
- }
- if (properties().mAnimationMatrix) {
- ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING,
- level * 2, "", properties().mAnimationMatrix, SK_MATRIX_ARGS(properties().mAnimationMatrix));
- }
- if (properties().mMatrixFlags != 0) {
- if (properties().mMatrixFlags == TRANSLATION) {
- ALOGD("%*sTranslate %.2f, %.2f, %.2f",
- level * 2, "", properties().mTranslationX, properties().mTranslationY, properties().mTranslationZ);
- } else {
- ALOGD("%*sConcatMatrix %p: " MATRIX_4_STRING,
- level * 2, "", properties().mTransformMatrix, MATRIX_4_ARGS(properties().mTransformMatrix));
- }
- }
-
- bool clipToBoundsNeeded = properties().mCaching ? false : properties().mClipToBounds;
- if (properties().mAlpha < 1) {
- if (properties().mCaching) {
- ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", properties().mAlpha);
- } else if (!properties().mHasOverlappingRendering) {
- ALOGD("%*sScaleAlpha %.2f", level * 2, "", properties().mAlpha);
- } else {
- int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
- if (clipToBoundsNeeded) {
- flags |= SkCanvas::kClipToLayer_SaveFlag;
- clipToBoundsNeeded = false; // clipping done by save layer
- }
- ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
- (float) 0, (float) 0, (float) properties().mRight - properties().mLeft, (float) properties().mBottom - properties().mTop,
- (int)(properties().mAlpha * 255), flags);
- }
- }
- if (clipToBoundsNeeded) {
- ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
- (float) properties().mRight - properties().mLeft, (float) properties().mBottom - properties().mTop);
- }
-}
-
-/*
- * For property operations, we pass a savecount of 0, since the operations aren't part of the
- * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in
- * base saveCount (i.e., how RestoreToCount uses saveCount + properties().mCount)
- */
-#define PROPERTY_SAVECOUNT 0
-
-template <class T>
-void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler,
- const int level) {
-#if DEBUG_DISPLAY_LIST
- outputViewProperties(level);
-#endif
- properties().updateMatrix();
- if (properties().mLeft != 0 || properties().mTop != 0) {
- renderer.translate(properties().mLeft, properties().mTop);
- }
- if (properties().mStaticMatrix) {
- renderer.concatMatrix(properties().mStaticMatrix);
- } else if (properties().mAnimationMatrix) {
- renderer.concatMatrix(properties().mAnimationMatrix);
- }
- if (properties().mMatrixFlags != 0) {
- if (properties().mMatrixFlags == TRANSLATION) {
- renderer.translate(properties().mTranslationX, properties().mTranslationY);
- } else {
- renderer.concatMatrix(*properties().mTransformMatrix);
- }
- }
- bool clipToBoundsNeeded = properties().mCaching ? false : properties().mClipToBounds;
- if (properties().mAlpha < 1) {
- if (properties().mCaching) {
- renderer.setOverrideLayerAlpha(properties().mAlpha);
- } else if (!properties().mHasOverlappingRendering) {
- renderer.scaleAlpha(properties().mAlpha);
- } else {
- // TODO: should be able to store the size of a DL at record time and not
- // have to pass it into this call. In fact, this information might be in the
- // location/size info that we store with the new native transform data.
- int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
- if (clipToBoundsNeeded) {
- saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
- clipToBoundsNeeded = false; // clipping done by saveLayer
- }
-
- SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
- 0, 0, properties().mRight - properties().mLeft, properties().mBottom - properties().mTop, properties().mAlpha * 255, saveFlags);
- handler(op, PROPERTY_SAVECOUNT, properties().mClipToBounds);
- }
- }
- if (clipToBoundsNeeded) {
- ClipRectOp* op = new (handler.allocator()) ClipRectOp(0, 0,
- properties().mRight - properties().mLeft, properties().mBottom - properties().mTop, SkRegion::kIntersect_Op);
- handler(op, PROPERTY_SAVECOUNT, properties().mClipToBounds);
- }
- if (CC_UNLIKELY(properties().mClipToOutline && !properties().mOutline.isEmpty())) {
- ClipPathOp* op = new (handler.allocator()) ClipPathOp(&properties().mOutline, SkRegion::kIntersect_Op);
- handler(op, PROPERTY_SAVECOUNT, properties().mClipToBounds);
- }
-}
-
-/**
- * Apply property-based transformations to input matrix
- *
- * If true3dTransform is set to true, the transform applied to the input matrix will use true 4x4
- * matrix computation instead of the Skia 3x3 matrix + camera hackery.
- */
-void RenderNode::applyViewPropertyTransforms(mat4& matrix, bool true3dTransform) {
- if (properties().mLeft != 0 || properties().mTop != 0) {
- matrix.translate(properties().mLeft, properties().mTop);
- }
- if (properties().mStaticMatrix) {
- mat4 stat(*properties().mStaticMatrix);
- matrix.multiply(stat);
- } else if (properties().mAnimationMatrix) {
- mat4 anim(*properties().mAnimationMatrix);
- matrix.multiply(anim);
- }
- if (properties().mMatrixFlags != 0) {
- properties().updateMatrix();
- if (properties().mMatrixFlags == TRANSLATION) {
- matrix.translate(properties().mTranslationX, properties().mTranslationY,
- true3dTransform ? properties().mTranslationZ : 0.0f);
- } else {
- if (!true3dTransform) {
- matrix.multiply(*properties().mTransformMatrix);
- } else {
- mat4 true3dMat;
- true3dMat.loadTranslate(
- properties().mPivotX + properties().mTranslationX,
- properties().mPivotY + properties().mTranslationY,
- properties().mTranslationZ);
- true3dMat.rotate(properties().mRotationX, 1, 0, 0);
- true3dMat.rotate(properties().mRotationY, 0, 1, 0);
- true3dMat.rotate(properties().mRotation, 0, 0, 1);
- true3dMat.scale(properties().mScaleX, properties().mScaleY, 1);
- true3dMat.translate(-properties().mPivotX, -properties().mPivotY);
-
- matrix.multiply(true3dMat);
- }
- }
- }
-}
-
-/**
- * Organizes the DisplayList hierarchy to prepare for background projection reordering.
- *
- * This should be called before a call to defer() or drawDisplayList()
- *
- * Each DisplayList that serves as a 3d root builds its list of composited children,
- * which are flagged to not draw in the standard draw loop.
- */
-void RenderNode::computeOrdering() {
- ATRACE_CALL();
- mProjectedNodes.clear();
-
- // TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that
- // transform properties are applied correctly to top level children
- if (mDisplayListData == NULL) return;
- for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
- DrawDisplayListOp* childOp = mDisplayListData->children[i];
- childOp->mDisplayList->computeOrderingImpl(childOp,
- &mProjectedNodes, &mat4::identity());
- }
-}
-
-void RenderNode::computeOrderingImpl(
- DrawDisplayListOp* opState,
- Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface,
- const mat4* transformFromProjectionSurface) {
- mProjectedNodes.clear();
- if (mDisplayListData == NULL || mDisplayListData->isEmpty()) return;
-
- // TODO: should avoid this calculation in most cases
- // TODO: just calculate single matrix, down to all leaf composited elements
- Matrix4 localTransformFromProjectionSurface(*transformFromProjectionSurface);
- localTransformFromProjectionSurface.multiply(opState->mTransformFromParent);
-
- if (properties().mProjectBackwards) {
- // composited projectee, flag for out of order draw, save matrix, and store in proj surface
- opState->mSkipInOrderDraw = true;
- opState->mTransformFromCompositingAncestor.load(localTransformFromProjectionSurface);
- compositedChildrenOfProjectionSurface->add(opState);
- } else {
- // standard in order draw
- opState->mSkipInOrderDraw = false;
- }
-
- if (mDisplayListData->children.size() > 0) {
- const bool isProjectionReceiver = mDisplayListData->projectionReceiveIndex >= 0;
- bool haveAppliedPropertiesToProjection = false;
- for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
- DrawDisplayListOp* childOp = mDisplayListData->children[i];
- RenderNode* child = childOp->mDisplayList;
-
- Vector<DrawDisplayListOp*>* projectionChildren = NULL;
- const mat4* projectionTransform = NULL;
- if (isProjectionReceiver && !child->properties().mProjectBackwards) {
- // if receiving projections, collect projecting descendent
-
- // Note that if a direct descendent is projecting backwards, we pass it's
- // grandparent projection collection, since it shouldn't project onto it's
- // parent, where it will already be drawing.
- projectionChildren = &mProjectedNodes;
- projectionTransform = &mat4::identity();
- } else {
- if (!haveAppliedPropertiesToProjection) {
- applyViewPropertyTransforms(localTransformFromProjectionSurface);
- haveAppliedPropertiesToProjection = true;
- }
- projectionChildren = compositedChildrenOfProjectionSurface;
- projectionTransform = &localTransformFromProjectionSurface;
- }
- child->computeOrderingImpl(childOp, projectionChildren, projectionTransform);
- }
- }
-
-}
-
-class DeferOperationHandler {
-public:
- DeferOperationHandler(DeferStateStruct& deferStruct, int level)
- : mDeferStruct(deferStruct), mLevel(level) {}
- inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
- operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds);
- }
- inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); }
-
-private:
- DeferStateStruct& mDeferStruct;
- const int mLevel;
-};
-
-void RenderNode::defer(DeferStateStruct& deferStruct, const int level) {
- DeferOperationHandler handler(deferStruct, level);
- iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level);
-}
-
-class ReplayOperationHandler {
-public:
- ReplayOperationHandler(ReplayStateStruct& replayStruct, int level)
- : mReplayStruct(replayStruct), mLevel(level) {}
- inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
-#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
- properties().mReplayStruct.mRenderer.eventMark(operation->name());
-#endif
- operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
- }
- inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); }
-
-private:
- ReplayStateStruct& mReplayStruct;
- const int mLevel;
-};
-
-void RenderNode::replay(ReplayStateStruct& replayStruct, const int level) {
- ReplayOperationHandler handler(replayStruct, level);
-
- replayStruct.mRenderer.startMark(mName.string());
- iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level);
- replayStruct.mRenderer.endMark();
-
- DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
- replayStruct.mDrawGlStatus);
-}
-
-void RenderNode::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes) {
- if (mDisplayListData == NULL || mDisplayListData->children.size() == 0) return;
-
- for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
- DrawDisplayListOp* childOp = mDisplayListData->children[i];
- RenderNode* child = childOp->mDisplayList;
- float childZ = child->properties().mTranslationZ;
-
- if (childZ != 0.0f) {
- zTranslatedNodes.add(ZDrawDisplayListOpPair(childZ, childOp));
- childOp->mSkipInOrderDraw = true;
- } else if (!child->properties().mProjectBackwards) {
- // regular, in order drawing DisplayList
- childOp->mSkipInOrderDraw = false;
- }
- }
-
- // Z sort 3d children (stable-ness makes z compare fall back to standard drawing order)
- std::stable_sort(zTranslatedNodes.begin(), zTranslatedNodes.end());
-}
-
-#define SHADOW_DELTA 0.1f
-
-template <class T>
-void RenderNode::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
- ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler) {
- const int size = zTranslatedNodes.size();
- if (size == 0
- || (mode == kNegativeZChildren && zTranslatedNodes[0].key > 0.0f)
- || (mode == kPositiveZChildren && zTranslatedNodes[size - 1].key < 0.0f)) {
- // no 3d children to draw
- return;
- }
-
- int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
- LinearAllocator& alloc = handler.allocator();
- ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, properties().mWidth, properties().mHeight,
- SkRegion::kIntersect_Op); // clip to 3d root bounds
- handler(clipOp, PROPERTY_SAVECOUNT, properties().mClipToBounds);
-
- /**
- * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters
- * with very similar Z heights to draw together.
- *
- * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are
- * underneath both, and neither's shadow is drawn on top of the other.
- */
- const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes);
- size_t drawIndex, shadowIndex, endIndex;
- if (mode == kNegativeZChildren) {
- drawIndex = 0;
- endIndex = nonNegativeIndex;
- shadowIndex = endIndex; // draw no shadows
- } else {
- drawIndex = nonNegativeIndex;
- endIndex = size;
- shadowIndex = drawIndex; // potentially draw shadow for each pos Z child
- }
- float lastCasterZ = 0.0f;
- while (shadowIndex < endIndex || drawIndex < endIndex) {
- if (shadowIndex < endIndex) {
- DrawDisplayListOp* casterOp = zTranslatedNodes[shadowIndex].value;
- RenderNode* caster = casterOp->mDisplayList;
- const float casterZ = zTranslatedNodes[shadowIndex].key;
- // attempt to render the shadow if the caster about to be drawn is its caster,
- // OR if its caster's Z value is similar to the previous potential caster
- if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) {
-
- if (caster->properties().mAlpha > 0.0f) {
- mat4 shadowMatrixXY(casterOp->mTransformFromParent);
- caster->applyViewPropertyTransforms(shadowMatrixXY);
-
- // Z matrix needs actual 3d transformation, so mapped z values will be correct
- mat4 shadowMatrixZ(casterOp->mTransformFromParent);
- caster->applyViewPropertyTransforms(shadowMatrixZ, true);
-
- DisplayListOp* shadowOp = new (alloc) DrawShadowOp(
- shadowMatrixXY, shadowMatrixZ,
- caster->properties().mAlpha, &(caster->properties().mOutline),
- caster->properties().mWidth, caster->properties().mHeight);
- handler(shadowOp, PROPERTY_SAVECOUNT, properties().mClipToBounds);
- }
-
- lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
- shadowIndex++;
- continue;
- }
- }
-
- // only the actual child DL draw needs to be in save/restore,
- // since it modifies the renderer's matrix
- int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
-
- DrawDisplayListOp* childOp = zTranslatedNodes[drawIndex].value;
- RenderNode* child = childOp->mDisplayList;
-
- renderer.concatMatrix(childOp->mTransformFromParent);
- childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
- handler(childOp, renderer.getSaveCount() - 1, properties().mClipToBounds);
- childOp->mSkipInOrderDraw = true;
-
- renderer.restoreToCount(restoreTo);
- drawIndex++;
- }
- handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, properties().mClipToBounds);
-}
-
-template <class T>
-void RenderNode::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) {
- int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
- LinearAllocator& alloc = handler.allocator();
- ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, properties().mWidth, properties().mHeight,
- SkRegion::kReplace_Op); // clip to projection surface root bounds
- handler(clipOp, PROPERTY_SAVECOUNT, properties().mClipToBounds);
-
- for (size_t i = 0; i < mProjectedNodes.size(); i++) {
- DrawDisplayListOp* childOp = mProjectedNodes[i];
-
- // matrix save, concat, and restore can be done safely without allocating operations
- int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
- renderer.concatMatrix(childOp->mTransformFromCompositingAncestor);
- childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
- handler(childOp, renderer.getSaveCount() - 1, properties().mClipToBounds);
- childOp->mSkipInOrderDraw = true;
- renderer.restoreToCount(restoreTo);
- }
- handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, properties().mClipToBounds);
-}
-
-/**
- * This function serves both defer and replay modes, and will organize the displayList's component
- * operations for a single frame:
- *
- * Every 'simple' state operation that affects just the matrix and alpha (or other factors of
- * DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom
- * defer logic) and operations in displayListOps are issued through the 'handler' which handles the
- * defer vs replay logic, per operation
- */
-template <class T>
-void RenderNode::iterate(OpenGLRenderer& renderer, T& handler, const int level) {
- if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging
- ALOGW("Error: %s is drawing after destruction", mName.string());
- CRASH();
- }
- if (mDisplayListData->isEmpty() || properties().mAlpha <= 0) {
- DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string());
- return;
- }
-
-#if DEBUG_DISPLAY_LIST
- Rect* clipRect = renderer.getClipRect();
- DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f",
- level * 2, "", this, mName.string(), clipRect->left, clipRect->top,
- clipRect->right, clipRect->bottom);
-#endif
-
- LinearAllocator& alloc = handler.allocator();
- int restoreTo = renderer.getSaveCount();
- handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
- PROPERTY_SAVECOUNT, properties().mClipToBounds);
-
- DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
- SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
-
- setViewProperties<T>(renderer, handler, level + 1);
-
- bool quickRejected = properties().mClipToBounds && renderer.quickRejectConservative(0, 0, properties().mWidth, properties().mHeight);
- if (!quickRejected) {
- Vector<ZDrawDisplayListOpPair> zTranslatedNodes;
- buildZSortedChildList(zTranslatedNodes);
-
- // for 3d root, draw children with negative z values
- iterate3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
-
- DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
- const int saveCountOffset = renderer.getSaveCount() - 1;
- const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
- for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
- DisplayListOp *op = mDisplayListData->displayListOps[i];
-
-#if DEBUG_DISPLAY_LIST
- op->output(level + 1);
-#endif
-
- logBuffer.writeCommand(level, op->name());
- handler(op, saveCountOffset, properties().mClipToBounds);
-
- if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
- iterateProjectedChildren(renderer, handler, level);
- }
- }
-
- // for 3d root, draw children with positive z values
- iterate3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
- }
-
- DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
- handler(new (alloc) RestoreToCountOp(restoreTo),
- PROPERTY_SAVECOUNT, properties().mClipToBounds);
- renderer.setOverrideLayerAlpha(1.0f);
-}
-
void DisplayListData::cleanupResources() {
Caches& caches = Caches::getInstance();
caches.unregisterFunctors(functorCount);
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index b80c1187648c..df5cba61d7cb 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -143,136 +143,6 @@ private:
void cleanupResources();
};
-/**
- * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties.
- *
- * Recording of canvas commands is somewhat similar to SkPicture, except the canvas-recording
- * functionality is split between DisplayListRenderer (which manages the recording), DisplayListData
- * (which holds the actual data), and DisplayList (which holds properties and performs playback onto
- * a renderer).
- *
- * Note that DisplayListData is swapped out from beneath an individual DisplayList when a view's
- * recorded stream of canvas operations is refreshed. The DisplayList (and its properties) stay
- * attached.
- */
-class RenderNode {
-public:
- ANDROID_API RenderNode();
- ANDROID_API ~RenderNode();
-
- // See flags defined in DisplayList.java
- enum ReplayFlag {
- kReplayFlag_ClipChildren = 0x1
- };
-
- ANDROID_API static void destroyDisplayListDeferred(RenderNode* displayList);
- ANDROID_API static void outputLogBuffer(int fd);
-
- ANDROID_API void setData(DisplayListData* newData);
-
- void computeOrdering();
- void defer(DeferStateStruct& deferStruct, const int level);
- void replay(ReplayStateStruct& replayStruct, const int level);
-
- ANDROID_API void output(uint32_t level = 1);
-
- bool isRenderable() const {
- return mDisplayListData && mDisplayListData->hasDrawOps;
- }
-
- void setName(const char* name) {
- if (name) {
- char* lastPeriod = strrchr(name, '.');
- if (lastPeriod) {
- mName.setTo(lastPeriod + 1);
- } else {
- mName.setTo(name);
- }
- }
- }
-
- RenderProperties& properties() {
- return mProperties;
- }
-
- bool isProjectionReceiver() {
- return properties().isProjectionReceiver();
- }
-
- int getWidth() {
- return properties().getWidth();
- }
-
- int getHeight() {
- return properties().getHeight();
- }
-
-private:
- typedef key_value_pair_t<float, DrawDisplayListOp*> ZDrawDisplayListOpPair;
-
- static size_t findNonNegativeIndex(const Vector<ZDrawDisplayListOpPair>& nodes) {
- for (size_t i = 0; i < nodes.size(); i++) {
- if (nodes[i].key >= 0.0f) return i;
- }
- return nodes.size();
- }
-
- enum ChildrenSelectMode {
- kNegativeZChildren,
- kPositiveZChildren
- };
-
- void outputViewProperties(const int level);
-
- void applyViewPropertyTransforms(mat4& matrix, bool true3dTransform = false);
-
- void computeOrderingImpl(DrawDisplayListOp* opState,
- Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface,
- const mat4* transformFromProjectionSurface);
-
- template <class T>
- inline void setViewProperties(OpenGLRenderer& renderer, T& handler, const int level);
-
- void buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes);
-
- template <class T>
- inline void iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
- ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler);
-
- template <class T>
- inline void iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level);
-
- template <class T>
- inline void iterate(OpenGLRenderer& renderer, T& handler, const int level);
-
- class TextContainer {
- public:
- size_t length() const {
- return mByteLength;
- }
-
- const char* text() const {
- return (const char*) mText;
- }
-
- size_t mByteLength;
- const char* mText;
- };
-
- String8 mName;
- bool mDestroyed; // used for debugging crash, TODO: remove once invalid state crash fixed
-
- RenderProperties mProperties;
- DisplayListData* mDisplayListData;
-
- /**
- * Draw time state - these properties are only set and used during rendering
- */
-
- // for projection surfaces, contains a list of all children items
- Vector<DrawDisplayListOp*> mProjectedNodes;
-}; // class DisplayList
-
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index e69e08ed2227..78c97e14d363 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -21,12 +21,12 @@
#include <private/hwui/DrawGlInfo.h>
-#include "DisplayList.h"
+#include "Caches.h"
#include "DeferredDisplayList.h"
#include "DisplayListLogBuffer.h"
#include "DisplayListOp.h"
#include "DisplayListRenderer.h"
-#include "Caches.h"
+#include "RenderNode.h"
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 65498a577c06..04c5a7372aae 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -22,9 +22,9 @@
#include <SkPath.h>
#include <cutils/compiler.h>
-#include "DisplayList.h"
#include "DisplayListLogBuffer.h"
#include "OpenGLRenderer.h"
+#include "RenderNode.h"
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 52176d4ef78b..bd9bfe95c057 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -18,12 +18,12 @@
#include <utils/Log.h>
-#include "DisplayList.h"
+#include "Caches.h"
#include "DeferredDisplayList.h"
#include "Layer.h"
#include "LayerRenderer.h"
#include "OpenGLRenderer.h"
-#include "Caches.h"
+#include "RenderNode.h"
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
new file mode 100644
index 000000000000..e371590b8120
--- /dev/null
+++ b/libs/hwui/RenderNode.cpp
@@ -0,0 +1,571 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_VIEW
+
+#include "RenderNode.h"
+
+#include <SkCanvas.h>
+#include <algorithm>
+
+#include <utils/Trace.h>
+
+#include "Debug.h"
+#include "DisplayListOp.h"
+#include "DisplayListLogBuffer.h"
+
+namespace android {
+namespace uirenderer {
+
+void RenderNode::outputLogBuffer(int fd) {
+ DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
+ if (logBuffer.isEmpty()) {
+ return;
+ }
+
+ FILE *file = fdopen(fd, "a");
+
+ fprintf(file, "\nRecent DisplayList operations\n");
+ logBuffer.outputCommands(file);
+
+ String8 cachesLog;
+ Caches::getInstance().dumpMemoryUsage(cachesLog);
+ fprintf(file, "\nCaches:\n%s", cachesLog.string());
+ fprintf(file, "\n");
+
+ fflush(file);
+}
+
+RenderNode::RenderNode() : mDestroyed(false), mDisplayListData(0) {
+}
+
+RenderNode::~RenderNode() {
+ LOG_ALWAYS_FATAL_IF(mDestroyed, "Double destroyed DisplayList %p", this);
+
+ mDestroyed = true;
+ delete mDisplayListData;
+}
+
+void RenderNode::destroyDisplayListDeferred(RenderNode* displayList) {
+ if (displayList) {
+ DISPLAY_LIST_LOGD("Deferring display list destruction");
+ Caches::getInstance().deleteDisplayListDeferred(displayList);
+ }
+}
+
+void RenderNode::setData(DisplayListData* data) {
+ delete mDisplayListData;
+ mDisplayListData = data;
+ if (mDisplayListData) {
+ Caches::getInstance().registerFunctors(mDisplayListData->functorCount);
+ }
+}
+
+/**
+ * This function is a simplified version of replay(), where we simply retrieve and log the
+ * display list. This function should remain in sync with the replay() function.
+ */
+void RenderNode::output(uint32_t level) {
+ ALOGD("%*sStart display list (%p, %s, render=%d)", (level - 1) * 2, "", this,
+ mName.string(), isRenderable());
+ ALOGD("%*s%s %d", level * 2, "", "Save",
+ SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+
+ outputViewProperties(level);
+ int flags = DisplayListOp::kOpLogFlag_Recurse;
+ for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
+ mDisplayListData->displayListOps[i]->output(level, flags);
+ }
+
+ ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string());
+}
+
+void RenderNode::outputViewProperties(const int level) {
+ properties().updateMatrix();
+ if (properties().mLeft != 0 || properties().mTop != 0) {
+ ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", properties().mLeft, properties().mTop);
+ }
+ if (properties().mStaticMatrix) {
+ ALOGD("%*sConcatMatrix (static) %p: " SK_MATRIX_STRING,
+ level * 2, "", properties().mStaticMatrix, SK_MATRIX_ARGS(properties().mStaticMatrix));
+ }
+ if (properties().mAnimationMatrix) {
+ ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING,
+ level * 2, "", properties().mAnimationMatrix, SK_MATRIX_ARGS(properties().mAnimationMatrix));
+ }
+ if (properties().mMatrixFlags != 0) {
+ if (properties().mMatrixFlags == TRANSLATION) {
+ ALOGD("%*sTranslate %.2f, %.2f, %.2f",
+ level * 2, "", properties().mTranslationX, properties().mTranslationY, properties().mTranslationZ);
+ } else {
+ ALOGD("%*sConcatMatrix %p: " MATRIX_4_STRING,
+ level * 2, "", properties().mTransformMatrix, MATRIX_4_ARGS(properties().mTransformMatrix));
+ }
+ }
+
+ bool clipToBoundsNeeded = properties().mCaching ? false : properties().mClipToBounds;
+ if (properties().mAlpha < 1) {
+ if (properties().mCaching) {
+ ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", properties().mAlpha);
+ } else if (!properties().mHasOverlappingRendering) {
+ ALOGD("%*sScaleAlpha %.2f", level * 2, "", properties().mAlpha);
+ } else {
+ int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
+ if (clipToBoundsNeeded) {
+ flags |= SkCanvas::kClipToLayer_SaveFlag;
+ clipToBoundsNeeded = false; // clipping done by save layer
+ }
+ ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
+ (float) 0, (float) 0, (float) properties().mRight - properties().mLeft, (float) properties().mBottom - properties().mTop,
+ (int)(properties().mAlpha * 255), flags);
+ }
+ }
+ if (clipToBoundsNeeded) {
+ ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
+ (float) properties().mRight - properties().mLeft, (float) properties().mBottom - properties().mTop);
+ }
+}
+
+/*
+ * For property operations, we pass a savecount of 0, since the operations aren't part of the
+ * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in
+ * base saveCount (i.e., how RestoreToCount uses saveCount + properties().mCount)
+ */
+#define PROPERTY_SAVECOUNT 0
+
+template <class T>
+void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler,
+ const int level) {
+#if DEBUG_DISPLAY_LIST
+ outputViewProperties(level);
+#endif
+ properties().updateMatrix();
+ if (properties().mLeft != 0 || properties().mTop != 0) {
+ renderer.translate(properties().mLeft, properties().mTop);
+ }
+ if (properties().mStaticMatrix) {
+ renderer.concatMatrix(properties().mStaticMatrix);
+ } else if (properties().mAnimationMatrix) {
+ renderer.concatMatrix(properties().mAnimationMatrix);
+ }
+ if (properties().mMatrixFlags != 0) {
+ if (properties().mMatrixFlags == TRANSLATION) {
+ renderer.translate(properties().mTranslationX, properties().mTranslationY);
+ } else {
+ renderer.concatMatrix(*properties().mTransformMatrix);
+ }
+ }
+ bool clipToBoundsNeeded = properties().mCaching ? false : properties().mClipToBounds;
+ if (properties().mAlpha < 1) {
+ if (properties().mCaching) {
+ renderer.setOverrideLayerAlpha(properties().mAlpha);
+ } else if (!properties().mHasOverlappingRendering) {
+ renderer.scaleAlpha(properties().mAlpha);
+ } else {
+ // TODO: should be able to store the size of a DL at record time and not
+ // have to pass it into this call. In fact, this information might be in the
+ // location/size info that we store with the new native transform data.
+ int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
+ if (clipToBoundsNeeded) {
+ saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
+ clipToBoundsNeeded = false; // clipping done by saveLayer
+ }
+
+ SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
+ 0, 0, properties().mRight - properties().mLeft, properties().mBottom - properties().mTop, properties().mAlpha * 255, saveFlags);
+ handler(op, PROPERTY_SAVECOUNT, properties().mClipToBounds);
+ }
+ }
+ if (clipToBoundsNeeded) {
+ ClipRectOp* op = new (handler.allocator()) ClipRectOp(0, 0,
+ properties().mRight - properties().mLeft, properties().mBottom - properties().mTop, SkRegion::kIntersect_Op);
+ handler(op, PROPERTY_SAVECOUNT, properties().mClipToBounds);
+ }
+ if (CC_UNLIKELY(properties().mClipToOutline && !properties().mOutline.isEmpty())) {
+ ClipPathOp* op = new (handler.allocator()) ClipPathOp(&properties().mOutline, SkRegion::kIntersect_Op);
+ handler(op, PROPERTY_SAVECOUNT, properties().mClipToBounds);
+ }
+}
+
+/**
+ * Apply property-based transformations to input matrix
+ *
+ * If true3dTransform is set to true, the transform applied to the input matrix will use true 4x4
+ * matrix computation instead of the Skia 3x3 matrix + camera hackery.
+ */
+void RenderNode::applyViewPropertyTransforms(mat4& matrix, bool true3dTransform) {
+ if (properties().mLeft != 0 || properties().mTop != 0) {
+ matrix.translate(properties().mLeft, properties().mTop);
+ }
+ if (properties().mStaticMatrix) {
+ mat4 stat(*properties().mStaticMatrix);
+ matrix.multiply(stat);
+ } else if (properties().mAnimationMatrix) {
+ mat4 anim(*properties().mAnimationMatrix);
+ matrix.multiply(anim);
+ }
+ if (properties().mMatrixFlags != 0) {
+ properties().updateMatrix();
+ if (properties().mMatrixFlags == TRANSLATION) {
+ matrix.translate(properties().mTranslationX, properties().mTranslationY,
+ true3dTransform ? properties().mTranslationZ : 0.0f);
+ } else {
+ if (!true3dTransform) {
+ matrix.multiply(*properties().mTransformMatrix);
+ } else {
+ mat4 true3dMat;
+ true3dMat.loadTranslate(
+ properties().mPivotX + properties().mTranslationX,
+ properties().mPivotY + properties().mTranslationY,
+ properties().mTranslationZ);
+ true3dMat.rotate(properties().mRotationX, 1, 0, 0);
+ true3dMat.rotate(properties().mRotationY, 0, 1, 0);
+ true3dMat.rotate(properties().mRotation, 0, 0, 1);
+ true3dMat.scale(properties().mScaleX, properties().mScaleY, 1);
+ true3dMat.translate(-properties().mPivotX, -properties().mPivotY);
+
+ matrix.multiply(true3dMat);
+ }
+ }
+ }
+}
+
+/**
+ * Organizes the DisplayList hierarchy to prepare for background projection reordering.
+ *
+ * This should be called before a call to defer() or drawDisplayList()
+ *
+ * Each DisplayList that serves as a 3d root builds its list of composited children,
+ * which are flagged to not draw in the standard draw loop.
+ */
+void RenderNode::computeOrdering() {
+ ATRACE_CALL();
+ mProjectedNodes.clear();
+
+ // TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that
+ // transform properties are applied correctly to top level children
+ if (mDisplayListData == NULL) return;
+ for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
+ DrawDisplayListOp* childOp = mDisplayListData->children[i];
+ childOp->mDisplayList->computeOrderingImpl(childOp,
+ &mProjectedNodes, &mat4::identity());
+ }
+}
+
+void RenderNode::computeOrderingImpl(
+ DrawDisplayListOp* opState,
+ Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface,
+ const mat4* transformFromProjectionSurface) {
+ mProjectedNodes.clear();
+ if (mDisplayListData == NULL || mDisplayListData->isEmpty()) return;
+
+ // TODO: should avoid this calculation in most cases
+ // TODO: just calculate single matrix, down to all leaf composited elements
+ Matrix4 localTransformFromProjectionSurface(*transformFromProjectionSurface);
+ localTransformFromProjectionSurface.multiply(opState->mTransformFromParent);
+
+ if (properties().mProjectBackwards) {
+ // composited projectee, flag for out of order draw, save matrix, and store in proj surface
+ opState->mSkipInOrderDraw = true;
+ opState->mTransformFromCompositingAncestor.load(localTransformFromProjectionSurface);
+ compositedChildrenOfProjectionSurface->add(opState);
+ } else {
+ // standard in order draw
+ opState->mSkipInOrderDraw = false;
+ }
+
+ if (mDisplayListData->children.size() > 0) {
+ const bool isProjectionReceiver = mDisplayListData->projectionReceiveIndex >= 0;
+ bool haveAppliedPropertiesToProjection = false;
+ for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
+ DrawDisplayListOp* childOp = mDisplayListData->children[i];
+ RenderNode* child = childOp->mDisplayList;
+
+ Vector<DrawDisplayListOp*>* projectionChildren = NULL;
+ const mat4* projectionTransform = NULL;
+ if (isProjectionReceiver && !child->properties().mProjectBackwards) {
+ // if receiving projections, collect projecting descendent
+
+ // Note that if a direct descendent is projecting backwards, we pass it's
+ // grandparent projection collection, since it shouldn't project onto it's
+ // parent, where it will already be drawing.
+ projectionChildren = &mProjectedNodes;
+ projectionTransform = &mat4::identity();
+ } else {
+ if (!haveAppliedPropertiesToProjection) {
+ applyViewPropertyTransforms(localTransformFromProjectionSurface);
+ haveAppliedPropertiesToProjection = true;
+ }
+ projectionChildren = compositedChildrenOfProjectionSurface;
+ projectionTransform = &localTransformFromProjectionSurface;
+ }
+ child->computeOrderingImpl(childOp, projectionChildren, projectionTransform);
+ }
+ }
+
+}
+
+class DeferOperationHandler {
+public:
+ DeferOperationHandler(DeferStateStruct& deferStruct, int level)
+ : mDeferStruct(deferStruct), mLevel(level) {}
+ inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
+ operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds);
+ }
+ inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); }
+
+private:
+ DeferStateStruct& mDeferStruct;
+ const int mLevel;
+};
+
+void RenderNode::defer(DeferStateStruct& deferStruct, const int level) {
+ DeferOperationHandler handler(deferStruct, level);
+ iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level);
+}
+
+class ReplayOperationHandler {
+public:
+ ReplayOperationHandler(ReplayStateStruct& replayStruct, int level)
+ : mReplayStruct(replayStruct), mLevel(level) {}
+ inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
+#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
+ properties().mReplayStruct.mRenderer.eventMark(operation->name());
+#endif
+ operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
+ }
+ inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); }
+
+private:
+ ReplayStateStruct& mReplayStruct;
+ const int mLevel;
+};
+
+void RenderNode::replay(ReplayStateStruct& replayStruct, const int level) {
+ ReplayOperationHandler handler(replayStruct, level);
+
+ replayStruct.mRenderer.startMark(mName.string());
+ iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level);
+ replayStruct.mRenderer.endMark();
+
+ DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
+ replayStruct.mDrawGlStatus);
+}
+
+void RenderNode::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes) {
+ if (mDisplayListData == NULL || mDisplayListData->children.size() == 0) return;
+
+ for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
+ DrawDisplayListOp* childOp = mDisplayListData->children[i];
+ RenderNode* child = childOp->mDisplayList;
+ float childZ = child->properties().mTranslationZ;
+
+ if (childZ != 0.0f) {
+ zTranslatedNodes.add(ZDrawDisplayListOpPair(childZ, childOp));
+ childOp->mSkipInOrderDraw = true;
+ } else if (!child->properties().mProjectBackwards) {
+ // regular, in order drawing DisplayList
+ childOp->mSkipInOrderDraw = false;
+ }
+ }
+
+ // Z sort 3d children (stable-ness makes z compare fall back to standard drawing order)
+ std::stable_sort(zTranslatedNodes.begin(), zTranslatedNodes.end());
+}
+
+#define SHADOW_DELTA 0.1f
+
+template <class T>
+void RenderNode::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
+ ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler) {
+ const int size = zTranslatedNodes.size();
+ if (size == 0
+ || (mode == kNegativeZChildren && zTranslatedNodes[0].key > 0.0f)
+ || (mode == kPositiveZChildren && zTranslatedNodes[size - 1].key < 0.0f)) {
+ // no 3d children to draw
+ return;
+ }
+
+ int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+ LinearAllocator& alloc = handler.allocator();
+ ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, properties().mWidth, properties().mHeight,
+ SkRegion::kIntersect_Op); // clip to 3d root bounds
+ handler(clipOp, PROPERTY_SAVECOUNT, properties().mClipToBounds);
+
+ /**
+ * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters
+ * with very similar Z heights to draw together.
+ *
+ * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are
+ * underneath both, and neither's shadow is drawn on top of the other.
+ */
+ const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes);
+ size_t drawIndex, shadowIndex, endIndex;
+ if (mode == kNegativeZChildren) {
+ drawIndex = 0;
+ endIndex = nonNegativeIndex;
+ shadowIndex = endIndex; // draw no shadows
+ } else {
+ drawIndex = nonNegativeIndex;
+ endIndex = size;
+ shadowIndex = drawIndex; // potentially draw shadow for each pos Z child
+ }
+ float lastCasterZ = 0.0f;
+ while (shadowIndex < endIndex || drawIndex < endIndex) {
+ if (shadowIndex < endIndex) {
+ DrawDisplayListOp* casterOp = zTranslatedNodes[shadowIndex].value;
+ RenderNode* caster = casterOp->mDisplayList;
+ const float casterZ = zTranslatedNodes[shadowIndex].key;
+ // attempt to render the shadow if the caster about to be drawn is its caster,
+ // OR if its caster's Z value is similar to the previous potential caster
+ if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) {
+
+ if (caster->properties().mAlpha > 0.0f) {
+ mat4 shadowMatrixXY(casterOp->mTransformFromParent);
+ caster->applyViewPropertyTransforms(shadowMatrixXY);
+
+ // Z matrix needs actual 3d transformation, so mapped z values will be correct
+ mat4 shadowMatrixZ(casterOp->mTransformFromParent);
+ caster->applyViewPropertyTransforms(shadowMatrixZ, true);
+
+ DisplayListOp* shadowOp = new (alloc) DrawShadowOp(
+ shadowMatrixXY, shadowMatrixZ,
+ caster->properties().mAlpha, &(caster->properties().mOutline),
+ caster->properties().mWidth, caster->properties().mHeight);
+ handler(shadowOp, PROPERTY_SAVECOUNT, properties().mClipToBounds);
+ }
+
+ lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
+ shadowIndex++;
+ continue;
+ }
+ }
+
+ // only the actual child DL draw needs to be in save/restore,
+ // since it modifies the renderer's matrix
+ int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
+
+ DrawDisplayListOp* childOp = zTranslatedNodes[drawIndex].value;
+ RenderNode* child = childOp->mDisplayList;
+
+ renderer.concatMatrix(childOp->mTransformFromParent);
+ childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
+ handler(childOp, renderer.getSaveCount() - 1, properties().mClipToBounds);
+ childOp->mSkipInOrderDraw = true;
+
+ renderer.restoreToCount(restoreTo);
+ drawIndex++;
+ }
+ handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, properties().mClipToBounds);
+}
+
+template <class T>
+void RenderNode::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) {
+ int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+ LinearAllocator& alloc = handler.allocator();
+ ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, properties().mWidth, properties().mHeight,
+ SkRegion::kReplace_Op); // clip to projection surface root bounds
+ handler(clipOp, PROPERTY_SAVECOUNT, properties().mClipToBounds);
+
+ for (size_t i = 0; i < mProjectedNodes.size(); i++) {
+ DrawDisplayListOp* childOp = mProjectedNodes[i];
+
+ // matrix save, concat, and restore can be done safely without allocating operations
+ int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
+ renderer.concatMatrix(childOp->mTransformFromCompositingAncestor);
+ childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
+ handler(childOp, renderer.getSaveCount() - 1, properties().mClipToBounds);
+ childOp->mSkipInOrderDraw = true;
+ renderer.restoreToCount(restoreTo);
+ }
+ handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, properties().mClipToBounds);
+}
+
+/**
+ * This function serves both defer and replay modes, and will organize the displayList's component
+ * operations for a single frame:
+ *
+ * Every 'simple' state operation that affects just the matrix and alpha (or other factors of
+ * DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom
+ * defer logic) and operations in displayListOps are issued through the 'handler' which handles the
+ * defer vs replay logic, per operation
+ */
+template <class T>
+void RenderNode::iterate(OpenGLRenderer& renderer, T& handler, const int level) {
+ if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging
+ ALOGW("Error: %s is drawing after destruction", mName.string());
+ CRASH();
+ }
+ if (mDisplayListData->isEmpty() || properties().mAlpha <= 0) {
+ DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string());
+ return;
+ }
+
+#if DEBUG_DISPLAY_LIST
+ Rect* clipRect = renderer.getClipRect();
+ DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f",
+ level * 2, "", this, mName.string(), clipRect->left, clipRect->top,
+ clipRect->right, clipRect->bottom);
+#endif
+
+ LinearAllocator& alloc = handler.allocator();
+ int restoreTo = renderer.getSaveCount();
+ handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
+ PROPERTY_SAVECOUNT, properties().mClipToBounds);
+
+ DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
+ SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
+
+ setViewProperties<T>(renderer, handler, level + 1);
+
+ bool quickRejected = properties().mClipToBounds && renderer.quickRejectConservative(0, 0, properties().mWidth, properties().mHeight);
+ if (!quickRejected) {
+ Vector<ZDrawDisplayListOpPair> zTranslatedNodes;
+ buildZSortedChildList(zTranslatedNodes);
+
+ // for 3d root, draw children with negative z values
+ iterate3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
+
+ DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
+ const int saveCountOffset = renderer.getSaveCount() - 1;
+ const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
+ for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
+ DisplayListOp *op = mDisplayListData->displayListOps[i];
+
+#if DEBUG_DISPLAY_LIST
+ op->output(level + 1);
+#endif
+
+ logBuffer.writeCommand(level, op->name());
+ handler(op, saveCountOffset, properties().mClipToBounds);
+
+ if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
+ iterateProjectedChildren(renderer, handler, level);
+ }
+ }
+
+ // for 3d root, draw children with positive z values
+ iterate3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
+ }
+
+ DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
+ handler(new (alloc) RestoreToCountOp(restoreTo),
+ PROPERTY_SAVECOUNT, properties().mClipToBounds);
+ renderer.setOverrideLayerAlpha(1.0f);
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
new file mode 100644
index 000000000000..177f33e10241
--- /dev/null
+++ b/libs/hwui/RenderNode.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef RENDERNODE_H
+#define RENDERNODE_H
+
+#ifndef LOG_TAG
+ #define LOG_TAG "OpenGLRenderer"
+#endif
+
+#include <SkCamera.h>
+#include <SkMatrix.h>
+
+#include <private/hwui/DrawGlInfo.h>
+
+#include <utils/KeyedVector.h>
+#include <utils/LinearAllocator.h>
+#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include <cutils/compiler.h>
+
+#include <androidfw/ResourceTypes.h>
+
+#include "Debug.h"
+#include "Matrix.h"
+#include "DeferredDisplayList.h"
+#include "DisplayList.h"
+#include "RenderProperties.h"
+
+class SkBitmap;
+class SkPaint;
+class SkPath;
+class SkRegion;
+
+namespace android {
+namespace uirenderer {
+
+class DeferredDisplayList;
+class DisplayListOp;
+class DisplayListRenderer;
+class OpenGLRenderer;
+class Rect;
+class Layer;
+class SkiaShader;
+
+class ClipRectOp;
+class SaveLayerOp;
+class SaveOp;
+class RestoreToCountOp;
+class DrawDisplayListOp;
+
+/**
+ * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties.
+ *
+ * Recording of canvas commands is somewhat similar to SkPicture, except the canvas-recording
+ * functionality is split between DisplayListRenderer (which manages the recording), DisplayListData
+ * (which holds the actual data), and DisplayList (which holds properties and performs playback onto
+ * a renderer).
+ *
+ * Note that DisplayListData is swapped out from beneath an individual DisplayList when a view's
+ * recorded stream of canvas operations is refreshed. The DisplayList (and its properties) stay
+ * attached.
+ */
+class RenderNode {
+public:
+ ANDROID_API RenderNode();
+ ANDROID_API ~RenderNode();
+
+ // See flags defined in DisplayList.java
+ enum ReplayFlag {
+ kReplayFlag_ClipChildren = 0x1
+ };
+
+ ANDROID_API static void destroyDisplayListDeferred(RenderNode* displayList);
+ ANDROID_API static void outputLogBuffer(int fd);
+
+ ANDROID_API void setData(DisplayListData* newData);
+
+ void computeOrdering();
+ void defer(DeferStateStruct& deferStruct, const int level);
+ void replay(ReplayStateStruct& replayStruct, const int level);
+
+ ANDROID_API void output(uint32_t level = 1);
+
+ bool isRenderable() const {
+ return mDisplayListData && mDisplayListData->hasDrawOps;
+ }
+
+ void setName(const char* name) {
+ if (name) {
+ char* lastPeriod = strrchr(name, '.');
+ if (lastPeriod) {
+ mName.setTo(lastPeriod + 1);
+ } else {
+ mName.setTo(name);
+ }
+ }
+ }
+
+ RenderProperties& properties() {
+ return mProperties;
+ }
+
+ bool isProjectionReceiver() {
+ return properties().isProjectionReceiver();
+ }
+
+ int getWidth() {
+ return properties().getWidth();
+ }
+
+ int getHeight() {
+ return properties().getHeight();
+ }
+
+private:
+ typedef key_value_pair_t<float, DrawDisplayListOp*> ZDrawDisplayListOpPair;
+
+ static size_t findNonNegativeIndex(const Vector<ZDrawDisplayListOpPair>& nodes) {
+ for (size_t i = 0; i < nodes.size(); i++) {
+ if (nodes[i].key >= 0.0f) return i;
+ }
+ return nodes.size();
+ }
+
+ enum ChildrenSelectMode {
+ kNegativeZChildren,
+ kPositiveZChildren
+ };
+
+ void outputViewProperties(const int level);
+
+ void applyViewPropertyTransforms(mat4& matrix, bool true3dTransform = false);
+
+ void computeOrderingImpl(DrawDisplayListOp* opState,
+ Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface,
+ const mat4* transformFromProjectionSurface);
+
+ template <class T>
+ inline void setViewProperties(OpenGLRenderer& renderer, T& handler, const int level);
+
+ void buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes);
+
+ template <class T>
+ inline void iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
+ ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler);
+
+ template <class T>
+ inline void iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level);
+
+ template <class T>
+ inline void iterate(OpenGLRenderer& renderer, T& handler, const int level);
+
+ class TextContainer {
+ public:
+ size_t length() const {
+ return mByteLength;
+ }
+
+ const char* text() const {
+ return (const char*) mText;
+ }
+
+ size_t mByteLength;
+ const char* mText;
+ };
+
+ String8 mName;
+ bool mDestroyed; // used for debugging crash, TODO: remove once invalid state crash fixed
+
+ RenderProperties mProperties;
+ DisplayListData* mDisplayListData;
+
+ /**
+ * Draw time state - these properties are only set and used during rendering
+ */
+
+ // for projection surfaces, contains a list of all children items
+ Vector<DrawDisplayListOp*> mProjectedNodes;
+}; // class RenderNode
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* RENDERNODE_H */
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index f81cd12d82ab..5fa0ba59efac 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -573,10 +573,8 @@ void SpotShadow::computeSpotShadow(bool isCasterOpaque, const Vector3* lightPoly
for (int j = 0; j < lightPolyLength; j++) {
int m = 0;
for (int i = 0; i < polyLength; i++) {
+ // After validating the input, deltaZ is guaranteed to be positive.
float deltaZ = lightPoly[j].z - poly[i].z;
- if (deltaZ == 0) {
- return;
- }
float ratioZ = lightPoly[j].z / deltaZ;
float x = lightPoly[j].x - ratioZ * (lightPoly[j].x - poly[i].x);
float y = lightPoly[j].y - ratioZ * (lightPoly[j].y - poly[i].y);
@@ -615,9 +613,6 @@ void SpotShadow::computeSpotShadow(bool isCasterOpaque, const Vector3* lightPoly
// If there is no real umbra, make a fake one.
for (int i = 0; i < polyLength; i++) {
float deltaZ = lightCenter.z - poly[i].z;
- if (deltaZ == 0) {
- return;
- }
float ratioZ = lightCenter.z / deltaZ;
float x = lightCenter.x - ratioZ * (lightCenter.x - poly[i].x);
float y = lightCenter.y - ratioZ * (lightCenter.y - poly[i].y);