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 "utils/StringUtils.h"
     18 #include "Texture.h"
     19 
     20 #include <cutils/compiler.h>
     21 #include <GpuMemoryTracker.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",
     37         "OffscreenBuffer",
     38         "Layer",
     39 };
     40 
     41 struct TypeStats {
     42     int totalSize = 0;
     43     int count = 0;
     44 };
     45 
     46 static std::array<TypeStats, NUM_TYPES> gObjectStats;
     47 static std::unordered_set<GpuMemoryTracker*> gObjectSet;
     48 
     49 void GpuMemoryTracker::notifySizeChanged(int newSize) {
     50     int delta = newSize - mSize;
     51     mSize = newSize;
     52     gObjectStats[static_cast<int>(mType)].totalSize += delta;
     53 }
     54 
     55 void GpuMemoryTracker::startTrackingObject() {
     56     auto result = gObjectSet.insert(this);
     57     LOG_ALWAYS_FATAL_IF(!result.second,
     58             "startTrackingObject() on %p failed, already being tracked!", this);
     59     gObjectStats[static_cast<int>(mType)].count++;
     60 }
     61 
     62 void GpuMemoryTracker::stopTrackingObject() {
     63     size_t removed = gObjectSet.erase(this);
     64     LOG_ALWAYS_FATAL_IF(removed != 1,
     65             "stopTrackingObject removed %zd, is %p not being tracked?",
     66             removed, this);
     67     gObjectStats[static_cast<int>(mType)].count--;
     68 }
     69 
     70 void GpuMemoryTracker::onGpuContextCreated() {
     71     LOG_ALWAYS_FATAL_IF(gGpuThread != 0, "We already have a gpu thread? "
     72             "current = %lu, gpu thread = %lu", pthread_self(), gGpuThread);
     73     gGpuThread = pthread_self();
     74 }
     75 
     76 void GpuMemoryTracker::onGpuContextDestroyed() {
     77     gGpuThread = 0;
     78     if (CC_UNLIKELY(gObjectSet.size() > 0)) {
     79         std::stringstream os;
     80         dump(os);
     81         ALOGE("%s", os.str().c_str());
     82         LOG_ALWAYS_FATAL("Leaked %zd GPU objects!", gObjectSet.size());
     83     }
     84 }
     85 
     86 void GpuMemoryTracker::dump() {
     87     std::stringstream strout;
     88     dump(strout);
     89     ALOGD("%s", strout.str().c_str());
     90 }
     91 
     92 void GpuMemoryTracker::dump(std::ostream& stream) {
     93     for (int type = 0; type < NUM_TYPES; type++) {
     94         const TypeStats& stats = gObjectStats[type];
     95         stream << TYPE_NAMES[type];
     96         stream << " is using " << SizePrinter{stats.totalSize};
     97         stream << ", count = " << stats.count;
     98         stream << std::endl;
     99     }
    100 }
    101 
    102 int GpuMemoryTracker::getInstanceCount(GpuObjectType type) {
    103     return gObjectStats[static_cast<int>(type)].count;
    104 }
    105 
    106 int GpuMemoryTracker::getTotalSize(GpuObjectType type) {
    107     return gObjectStats[static_cast<int>(type)].totalSize;
    108 }
    109 
    110 void GpuMemoryTracker::onFrameCompleted() {
    111     if (ATRACE_ENABLED()) {
    112         char buf[128];
    113         for (int type = 0; type < NUM_TYPES; type++) {
    114             snprintf(buf, 128, "hwui_%s", TYPE_NAMES[type]);
    115             const TypeStats& stats = gObjectStats[type];
    116             ATRACE_INT(buf, stats.totalSize);
    117             snprintf(buf, 128, "hwui_%s_count", TYPE_NAMES[type]);
    118             ATRACE_INT(buf, stats.count);
    119         }
    120     }
    121 
    122     std::vector<const Texture*> freeList;
    123     for (const auto& obj : gObjectSet) {
    124         if (obj->objectType() == GpuObjectType::Texture) {
    125             const Texture* texture = static_cast<Texture*>(obj);
    126             if (texture->cleanup) {
    127                 ALOGE("Leaked texture marked for cleanup! id=%u, size %ux%u",
    128                         texture->id(), texture->width(), texture->height());
    129                 freeList.push_back(texture);
    130             }
    131         }
    132     }
    133     for (auto& texture : freeList) {
    134         const_cast<Texture*>(texture)->deleteTexture();
    135         delete texture;
    136     }
    137 }
    138 
    139 } // namespace uirenderer
    140 } // namespace android;
    141