diff options
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/androidfw/Asset.cpp | 18 | ||||
| -rw-r--r-- | libs/androidfw/BackupData.cpp | 2 | ||||
| -rw-r--r-- | libs/androidfw/BackupHelpers.cpp | 6 | ||||
| -rw-r--r-- | libs/androidfw/CursorWindow.cpp | 16 | ||||
| -rw-r--r-- | libs/androidfw/ResourceTypes.cpp | 150 | ||||
| -rw-r--r-- | libs/androidfw/ZipUtils.cpp | 4 | ||||
| -rw-r--r-- | libs/hwui/Android.mk | 1 | ||||
| -rw-r--r-- | libs/hwui/DeferredLayerUpdater.h | 2 | ||||
| -rw-r--r-- | libs/hwui/DisplayList.cpp | 537 | ||||
| -rw-r--r-- | libs/hwui/DisplayList.h | 130 | ||||
| -rw-r--r-- | libs/hwui/DisplayListRenderer.cpp | 4 | ||||
| -rw-r--r-- | libs/hwui/DisplayListRenderer.h | 2 | ||||
| -rw-r--r-- | libs/hwui/Layer.cpp | 4 | ||||
| -rw-r--r-- | libs/hwui/RenderNode.cpp | 571 | ||||
| -rw-r--r-- | libs/hwui/RenderNode.h | 200 | ||||
| -rw-r--r-- | libs/hwui/SpotShadow.cpp | 7 |
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); |