blob: 612bfde1a3fa4f4517c64bb05c4aef3986884e63 [file] [log] [blame]
John Reck38e0c322015-11-10 12:19:17 -08001/*
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
John Reck38e0c322015-11-10 12:19:17 -080017#include "Texture.h"
John Reck1bcacfd2017-11-03 10:12:19 -070018#include "utils/StringUtils.h"
John Reck38e0c322015-11-10 12:19:17 -080019
John Reck38e0c322015-11-10 12:19:17 -080020#include <GpuMemoryTracker.h>
John Reck1bcacfd2017-11-03 10:12:19 -070021#include <cutils/compiler.h>
John Reck38e0c322015-11-10 12:19:17 -080022#include <utils/Trace.h>
23#include <array>
24#include <sstream>
25#include <unordered_set>
26#include <vector>
27
28namespace android {
29namespace uirenderer {
30
31pthread_t gGpuThread = 0;
32
33#define NUM_TYPES static_cast<int>(GpuObjectType::TypeCount)
34
35const char* TYPE_NAMES[] = {
John Reck1bcacfd2017-11-03 10:12:19 -070036 "Texture", "OffscreenBuffer", "Layer",
John Reck38e0c322015-11-10 12:19:17 -080037};
38
39struct TypeStats {
40 int totalSize = 0;
41 int count = 0;
42};
43
44static std::array<TypeStats, NUM_TYPES> gObjectStats;
45static std::unordered_set<GpuMemoryTracker*> gObjectSet;
46
47void GpuMemoryTracker::notifySizeChanged(int newSize) {
48 int delta = newSize - mSize;
49 mSize = newSize;
50 gObjectStats[static_cast<int>(mType)].totalSize += delta;
51}
52
53void GpuMemoryTracker::startTrackingObject() {
54 auto result = gObjectSet.insert(this);
55 LOG_ALWAYS_FATAL_IF(!result.second,
John Reck1bcacfd2017-11-03 10:12:19 -070056 "startTrackingObject() on %p failed, already being tracked!", this);
John Reck38e0c322015-11-10 12:19:17 -080057 gObjectStats[static_cast<int>(mType)].count++;
58}
59
60void GpuMemoryTracker::stopTrackingObject() {
61 size_t removed = gObjectSet.erase(this);
John Reck1bcacfd2017-11-03 10:12:19 -070062 LOG_ALWAYS_FATAL_IF(removed != 1, "stopTrackingObject removed %zd, is %p not being tracked?",
63 removed, this);
John Reck38e0c322015-11-10 12:19:17 -080064 gObjectStats[static_cast<int>(mType)].count--;
65}
66
Greg Daniel45ec62b2017-01-04 14:27:00 -050067void GpuMemoryTracker::onGpuContextCreated() {
John Reck1bcacfd2017-11-03 10:12:19 -070068 LOG_ALWAYS_FATAL_IF(gGpuThread != 0,
69 "We already have a gpu thread? "
70 "current = %lu, gpu thread = %lu",
71 pthread_self(), gGpuThread);
John Reck38e0c322015-11-10 12:19:17 -080072 gGpuThread = pthread_self();
73}
74
Greg Daniel45ec62b2017-01-04 14:27:00 -050075void GpuMemoryTracker::onGpuContextDestroyed() {
John Reck38e0c322015-11-10 12:19:17 -080076 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
85void GpuMemoryTracker::dump() {
86 std::stringstream strout;
87 dump(strout);
88 ALOGD("%s", strout.str().c_str());
89}
90
91void 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
101int GpuMemoryTracker::getInstanceCount(GpuObjectType type) {
102 return gObjectStats[static_cast<int>(type)].count;
103}
104
105int GpuMemoryTracker::getTotalSize(GpuObjectType type) {
106 return gObjectStats[static_cast<int>(type)].totalSize;
107}
108
109void 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) {
John Reck1bcacfd2017-11-03 10:12:19 -0700126 ALOGE("Leaked texture marked for cleanup! id=%u, size %ux%u", texture->id(),
127 texture->width(), texture->height());
John Reck38e0c322015-11-10 12:19:17 -0800128 freeList.push_back(texture);
129 }
130 }
131 }
132 for (auto& texture : freeList) {
133 const_cast<Texture*>(texture)->deleteTexture();
134 delete texture;
135 }
136}
137
John Reck1bcacfd2017-11-03 10:12:19 -0700138} // namespace uirenderer
139} // namespace android;