Home | History | Annotate | Download | only in hwui
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "Texture.h"
     18 #include "utils/StringUtils.h"
     19 
     20 #include <GpuMemoryTracker.h>
     21 #include <cutils/compiler.h>
     22 #include <utils/Trace.h>
     23 #include <array>
     24 #include <sstream>
     25 #include <unordered_set>
     26 #include <vector>
     27 
     28 namespace android {
     29 namespace uirenderer {
     30 
     31 pthread_t gGpuThread = 0;
     32 
     33 #define NUM_TYPES static_cast<int>(GpuObjectType::TypeCount)
     34 
     35 const char* TYPE_NAMES[] = {
     36         "Texture", "OffscreenBuffer", "Layer",
     37 };
     38 
     39 struct TypeStats {
     40     int totalSize = 0;
     41     int count = 0;
     42 };
     43 
     44 static std::array<TypeStats, NUM_TYPES> gObjectStats;
     45 static std::unordered_set<GpuMemoryTracker*> gObjectSet;
     46 
     47 void GpuMemoryTracker::notifySizeChanged(int newSize) {
     48     int delta = newSize - mSize;
     49     mSize = newSize;
     50     gObjectStats[static_cast<int>(mType)].totalSize += delta;
     51 }
     52 
     53 void GpuMemoryTracker::startTrackingObject() {
     54     auto result = gObjectSet.insert(this);
     55     LOG_ALWAYS_FATAL_IF(!result.second,
     56                         "startTrackingObject() on %p failed, already being tracked!", this);
     57     gObjectStats[static_cast<int>(mType)].count++;
     58 }
     59 
     60 void GpuMemoryTracker::stopTrackingObject() {
     61     size_t removed = gObjectSet.erase(this);
     62     LOG_ALWAYS_FATAL_IF(removed != 1, "stopTrackingObject removed %zd, is %p not being tracked?",
     63                         removed, this);
     64     gObjectStats[static_cast<int>(mType)].count--;
     65 }
     66 
     67 void GpuMemoryTracker::onGpuContextCreated() {
     68     LOG_ALWAYS_FATAL_IF(gGpuThread != 0,
     69                         "We already have a gpu thread? "
     70                         "current = %lu, gpu thread = %lu",
     71                         pthread_self(), gGpuThread);
     72     gGpuThread = pthread_self();
     73 }
     74 
     75 void GpuMemoryTracker::onGpuContextDestroyed() {
     76     gGpuThread = 0;
     77     if (CC_UNLIKELY(gObjectSet.size() > 0)) {
     78         std::stringstream os;
     79         dump(os);
     80         ALOGE("%s", os.str().c_str());
     81         LOG_ALWAYS_FATAL("Leaked %zd GPU objects!", gObjectSet.size());
     82     }
     83 }
     84 
     85 void GpuMemoryTracker::dump() {
     86     std::stringstream strout;
     87     dump(strout);
     88     ALOGD("%s", strout.str().c_str());
     89 }
     90 
     91 void GpuMemoryTracker::dump(std::ostream& stream) {
     92     for (int type = 0; type < NUM_TYPES; type++) {
     93         const TypeStats& stats = gObjectStats[type];
     94         stream << TYPE_NAMES[type];
     95         stream << " is using " << SizePrinter{stats.totalSize};
     96         stream << ", count = " << stats.count;
     97         stream << std::endl;
     98     }
     99 }
    100 
    101 int GpuMemoryTracker::getInstanceCount(GpuObjectType type) {
    102     return gObjectStats[static_cast<int>(type)].count;
    103 }
    104 
    105 int GpuMemoryTracker::getTotalSize(GpuObjectType type) {
    106     return gObjectStats[static_cast<int>(type)].totalSize;
    107 }
    108 
    109 void GpuMemoryTracker::onFrameCompleted() {
    110     if (ATRACE_ENABLED()) {
    111         char buf[128];
    112         for (int type = 0; type < NUM_TYPES; type++) {
    113             snprintf(buf, 128, "hwui_%s", TYPE_NAMES[type]);
    114             const TypeStats& stats = gObjectStats[type];
    115             ATRACE_INT(buf, stats.totalSize);
    116             snprintf(buf, 128, "hwui_%s_count", TYPE_NAMES[type]);
    117             ATRACE_INT(buf, stats.count);
    118         }
    119     }
    120 
    121     std::vector<const Texture*> freeList;
    122     for (const auto& obj : gObjectSet) {
    123         if (obj->objectType() == GpuObjectType::Texture) {
    124             const Texture* texture = static_cast<Texture*>(obj);
    125             if (texture->cleanup) {
    126                 ALOGE("Leaked texture marked for cleanup! id=%u, size %ux%u", texture->id(),
    127                       texture->width(), texture->height());
    128                 freeList.push_back(texture);
    129             }
    130         }
    131     }
    132     for (auto& texture : freeList) {
    133         const_cast<Texture*>(texture)->deleteTexture();
    134         delete texture;
    135     }
    136 }
    137 
    138 }  // namespace uirenderer
    139 }  // namespace android;
    140