Merge "Add memory tracing in HWUI"
This commit is contained in:
committed by
Android (Google) Code Review
commit
a2eb784577
@@ -215,6 +215,7 @@ cc_defaults {
|
||||
android: {
|
||||
|
||||
srcs: [
|
||||
"pipeline/skia/ATraceMemoryDump.cpp",
|
||||
"pipeline/skia/GLFunctorDrawable.cpp",
|
||||
"pipeline/skia/LayerDrawable.cpp",
|
||||
"pipeline/skia/ShaderCache.cpp",
|
||||
@@ -244,7 +245,6 @@ cc_defaults {
|
||||
"DeviceInfo.cpp",
|
||||
"FrameInfo.cpp",
|
||||
"FrameInfoVisualizer.cpp",
|
||||
"GpuMemoryTracker.cpp",
|
||||
"HardwareBitmapUploader.cpp",
|
||||
"HWUIProperties.sysprop",
|
||||
"JankTracker.cpp",
|
||||
@@ -325,7 +325,6 @@ cc_test {
|
||||
"tests/unit/DamageAccumulatorTests.cpp",
|
||||
"tests/unit/DeferredLayerUpdaterTests.cpp",
|
||||
"tests/unit/FatVectorTests.cpp",
|
||||
"tests/unit/GpuMemoryTrackerTests.cpp",
|
||||
"tests/unit/GraphicsStatsServiceTests.cpp",
|
||||
"tests/unit/LayerUpdateQueueTests.cpp",
|
||||
"tests/unit/LinearAllocatorTests.cpp",
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
#include "utils/StringUtils.h"
|
||||
|
||||
#include <GpuMemoryTracker.h>
|
||||
#include <cutils/compiler.h>
|
||||
#include <utils/Trace.h>
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
pthread_t gGpuThread = 0;
|
||||
|
||||
#define NUM_TYPES static_cast<int>(GpuObjectType::TypeCount)
|
||||
|
||||
const char* TYPE_NAMES[] = {
|
||||
"Texture", "OffscreenBuffer", "Layer",
|
||||
};
|
||||
|
||||
struct TypeStats {
|
||||
int totalSize = 0;
|
||||
int count = 0;
|
||||
};
|
||||
|
||||
static std::array<TypeStats, NUM_TYPES> gObjectStats;
|
||||
static std::unordered_set<GpuMemoryTracker*> gObjectSet;
|
||||
|
||||
void GpuMemoryTracker::notifySizeChanged(int newSize) {
|
||||
int delta = newSize - mSize;
|
||||
mSize = newSize;
|
||||
gObjectStats[static_cast<int>(mType)].totalSize += delta;
|
||||
}
|
||||
|
||||
void GpuMemoryTracker::startTrackingObject() {
|
||||
auto result = gObjectSet.insert(this);
|
||||
LOG_ALWAYS_FATAL_IF(!result.second,
|
||||
"startTrackingObject() on %p failed, already being tracked!", this);
|
||||
gObjectStats[static_cast<int>(mType)].count++;
|
||||
}
|
||||
|
||||
void GpuMemoryTracker::stopTrackingObject() {
|
||||
size_t removed = gObjectSet.erase(this);
|
||||
LOG_ALWAYS_FATAL_IF(removed != 1, "stopTrackingObject removed %zd, is %p not being tracked?",
|
||||
removed, this);
|
||||
gObjectStats[static_cast<int>(mType)].count--;
|
||||
}
|
||||
|
||||
void GpuMemoryTracker::onGpuContextCreated() {
|
||||
LOG_ALWAYS_FATAL_IF(gGpuThread != 0,
|
||||
"We already have a gpu thread? "
|
||||
"current = %lu, gpu thread = %lu",
|
||||
pthread_self(), gGpuThread);
|
||||
gGpuThread = pthread_self();
|
||||
}
|
||||
|
||||
void GpuMemoryTracker::onGpuContextDestroyed() {
|
||||
gGpuThread = 0;
|
||||
if (CC_UNLIKELY(gObjectSet.size() > 0)) {
|
||||
std::stringstream os;
|
||||
dump(os);
|
||||
ALOGE("%s", os.str().c_str());
|
||||
LOG_ALWAYS_FATAL("Leaked %zd GPU objects!", gObjectSet.size());
|
||||
}
|
||||
}
|
||||
|
||||
void GpuMemoryTracker::dump() {
|
||||
std::stringstream strout;
|
||||
dump(strout);
|
||||
ALOGD("%s", strout.str().c_str());
|
||||
}
|
||||
|
||||
void GpuMemoryTracker::dump(std::ostream& stream) {
|
||||
for (int type = 0; type < NUM_TYPES; type++) {
|
||||
const TypeStats& stats = gObjectStats[type];
|
||||
stream << TYPE_NAMES[type];
|
||||
stream << " is using " << SizePrinter{stats.totalSize};
|
||||
stream << ", count = " << stats.count;
|
||||
stream << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int GpuMemoryTracker::getInstanceCount(GpuObjectType type) {
|
||||
return gObjectStats[static_cast<int>(type)].count;
|
||||
}
|
||||
|
||||
int GpuMemoryTracker::getTotalSize(GpuObjectType type) {
|
||||
return gObjectStats[static_cast<int>(type)].totalSize;
|
||||
}
|
||||
|
||||
void GpuMemoryTracker::onFrameCompleted() {
|
||||
if (ATRACE_ENABLED()) {
|
||||
char buf[128];
|
||||
for (int type = 0; type < NUM_TYPES; type++) {
|
||||
snprintf(buf, 128, "hwui_%s", TYPE_NAMES[type]);
|
||||
const TypeStats& stats = gObjectStats[type];
|
||||
ATRACE_INT(buf, stats.totalSize);
|
||||
snprintf(buf, 128, "hwui_%s_count", TYPE_NAMES[type]);
|
||||
ATRACE_INT(buf, stats.count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android;
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <pthread.h>
|
||||
#include <ostream>
|
||||
|
||||
#include <log/log.h>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
extern pthread_t gGpuThread;
|
||||
|
||||
#define ASSERT_GPU_THREAD() \
|
||||
LOG_ALWAYS_FATAL_IF(!pthread_equal(gGpuThread, pthread_self()), \
|
||||
"Error, %p of type %d (size=%d) used on wrong thread! cur thread %lu " \
|
||||
"!= gpu thread %lu", \
|
||||
this, static_cast<int>(mType), mSize, pthread_self(), gGpuThread)
|
||||
|
||||
enum class GpuObjectType {
|
||||
Texture = 0,
|
||||
OffscreenBuffer,
|
||||
Layer,
|
||||
|
||||
TypeCount,
|
||||
};
|
||||
|
||||
class GpuMemoryTracker {
|
||||
public:
|
||||
GpuObjectType objectType() { return mType; }
|
||||
int objectSize() { return mSize; }
|
||||
|
||||
static void onGpuContextCreated();
|
||||
static void onGpuContextDestroyed();
|
||||
static void dump();
|
||||
static void dump(std::ostream& stream);
|
||||
static int getInstanceCount(GpuObjectType type);
|
||||
static int getTotalSize(GpuObjectType type);
|
||||
static void onFrameCompleted();
|
||||
|
||||
protected:
|
||||
explicit GpuMemoryTracker(GpuObjectType type) : mType(type) {
|
||||
ASSERT_GPU_THREAD();
|
||||
startTrackingObject();
|
||||
}
|
||||
|
||||
~GpuMemoryTracker() {
|
||||
notifySizeChanged(0);
|
||||
stopTrackingObject();
|
||||
}
|
||||
|
||||
void notifySizeChanged(int newSize);
|
||||
|
||||
private:
|
||||
void startTrackingObject();
|
||||
void stopTrackingObject();
|
||||
|
||||
int mSize = 0;
|
||||
GpuObjectType mType;
|
||||
};
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android;
|
||||
175
libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
Normal file
175
libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
#include "ATraceMemoryDump.h"
|
||||
|
||||
#include <utils/Trace.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
namespace skiapipeline {
|
||||
|
||||
// When purgeable is INVALID_TIME it won't be logged at all.
|
||||
#define INVALID_TIME -1
|
||||
|
||||
/**
|
||||
* Skia invokes the following SkTraceMemoryDump functions:
|
||||
* 1. dumpNumericValue (dumpName, units="bytes", valueName="size")
|
||||
* 2. dumpStringValue (dumpName, valueName="type") [optional -> for example CPU memory does not
|
||||
* invoke dumpStringValue]
|
||||
* 3. dumpNumericValue (dumpName, units="bytes", valueName="purgeable_size") [optional]
|
||||
* 4. setMemoryBacking(dumpName, backingType) [optional -> for example Vulkan GPU resources do not
|
||||
* invoke setMemoryBacking]
|
||||
*
|
||||
* ATraceMemoryDump calculates memory category first by looking at the "type" string passed to
|
||||
* dumpStringValue and then by looking at "backingType" passed to setMemoryBacking.
|
||||
* Only GPU Texture memory is tracked separately and everything else is grouped as one
|
||||
* "GPU Memory" category.
|
||||
*/
|
||||
static std::unordered_map<const char*, const char*> sResourceMap = {
|
||||
{"malloc", "Graphics CPU Memory"}, // taken from setMemoryBacking(backingType)
|
||||
{"gl_texture", "Graphics Texture Memory"}, // taken from setMemoryBacking(backingType)
|
||||
{"Texture",
|
||||
"Graphics Texture Memory"}, // taken from dumpStringValue(value, valueName="type")
|
||||
// Uncomment categories below to split "GPU Memory" into more brackets for debugging.
|
||||
/*{"vk_buffer", "vk_buffer"},
|
||||
{"gl_renderbuffer", "gl_renderbuffer"},
|
||||
{"gl_buffer", "gl_buffer"},
|
||||
{"RenderTarget", "RenderTarget"},
|
||||
{"Stencil", "Stencil"},
|
||||
{"Path Data", "Path Data"},
|
||||
{"Buffer Object", "Buffer Object"},
|
||||
{"Surface", "Surface"},*/
|
||||
};
|
||||
|
||||
ATraceMemoryDump::ATraceMemoryDump() {
|
||||
mLastDumpName.reserve(100);
|
||||
mCategory.reserve(100);
|
||||
}
|
||||
|
||||
void ATraceMemoryDump::dumpNumericValue(const char* dumpName, const char* valueName,
|
||||
const char* units, uint64_t value) {
|
||||
if (!strcmp(units, "bytes")) {
|
||||
recordAndResetCountersIfNeeded(dumpName);
|
||||
if (!strcmp(valueName, "size")) {
|
||||
mLastDumpValue = value;
|
||||
} else if (!strcmp(valueName, "purgeable_size")) {
|
||||
mLastPurgeableDumpValue = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ATraceMemoryDump::dumpStringValue(const char* dumpName, const char* valueName,
|
||||
const char* value) {
|
||||
if (!strcmp(valueName, "type")) {
|
||||
recordAndResetCountersIfNeeded(dumpName);
|
||||
auto categoryIt = sResourceMap.find(value);
|
||||
if (categoryIt != sResourceMap.end()) {
|
||||
mCategory = categoryIt->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ATraceMemoryDump::setMemoryBacking(const char* dumpName, const char* backingType,
|
||||
const char* backingObjectId) {
|
||||
recordAndResetCountersIfNeeded(dumpName);
|
||||
auto categoryIt = sResourceMap.find(backingType);
|
||||
if (categoryIt != sResourceMap.end()) {
|
||||
mCategory = categoryIt->second;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* startFrame is invoked before dumping anything. It resets counters from the previous frame.
|
||||
* This is important, because if there is no new data for a given category trace would assume
|
||||
* usage has not changed (instead of reporting 0).
|
||||
*/
|
||||
void ATraceMemoryDump::startFrame() {
|
||||
resetCurrentCounter("");
|
||||
for (auto& it : mCurrentValues) {
|
||||
// Once a category is observed in at least one frame, it is always reported in subsequent
|
||||
// frames (even if it is 0). Not logging a category to ATRACE would mean its value has not
|
||||
// changed since the previous frame, which is not what we want.
|
||||
it.second.time = 0;
|
||||
// If purgeableTime is INVALID_TIME, then logTraces won't log it at all.
|
||||
if (it.second.purgeableTime != INVALID_TIME) {
|
||||
it.second.purgeableTime = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* logTraces reads from mCurrentValues and logs the counters with ATRACE.
|
||||
*/
|
||||
void ATraceMemoryDump::logTraces() {
|
||||
// Accumulate data from last dumpName
|
||||
recordAndResetCountersIfNeeded("");
|
||||
for (auto& it : mCurrentValues) {
|
||||
ATRACE_INT64(it.first.c_str(), it.second.time);
|
||||
if (it.second.purgeableTime != INVALID_TIME) {
|
||||
ATRACE_INT64((std::string("Purgeable ") + it.first).c_str(), it.second.purgeableTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* recordAndResetCountersIfNeeded reads memory usage from mLastDumpValue/mLastPurgeableDumpValue and
|
||||
* accumulates in mCurrentValues[category]. It makes provision to create a new category and track
|
||||
* purgeable memory only if there is at least one observation.
|
||||
* recordAndResetCountersIfNeeded won't do anything until all the information for a given dumpName
|
||||
* is received.
|
||||
*/
|
||||
void ATraceMemoryDump::recordAndResetCountersIfNeeded(const char* dumpName) {
|
||||
if (!mLastDumpName.compare(dumpName)) {
|
||||
// Still waiting for more data for current dumpName.
|
||||
return;
|
||||
}
|
||||
|
||||
// First invocation will have an empty mLastDumpName.
|
||||
if (!mLastDumpName.empty()) {
|
||||
// A new dumpName observed -> store the data already collected.
|
||||
auto memoryCounter = mCurrentValues.find(mCategory);
|
||||
if (memoryCounter != mCurrentValues.end()) {
|
||||
memoryCounter->second.time += mLastDumpValue;
|
||||
if (mLastPurgeableDumpValue != INVALID_TIME) {
|
||||
if (memoryCounter->second.purgeableTime == INVALID_TIME) {
|
||||
memoryCounter->second.purgeableTime = mLastPurgeableDumpValue;
|
||||
} else {
|
||||
memoryCounter->second.purgeableTime += mLastPurgeableDumpValue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mCurrentValues[mCategory] = {mLastDumpValue, mLastPurgeableDumpValue};
|
||||
}
|
||||
}
|
||||
|
||||
// Reset counters and default category for the newly observed "dumpName".
|
||||
resetCurrentCounter(dumpName);
|
||||
}
|
||||
|
||||
void ATraceMemoryDump::resetCurrentCounter(const char* dumpName) {
|
||||
mLastDumpValue = 0;
|
||||
mLastPurgeableDumpValue = INVALID_TIME;
|
||||
mLastDumpName = dumpName;
|
||||
// Categories not listed in sResourceMap are reported as "GPU memory"
|
||||
mCategory = "GPU Memory";
|
||||
}
|
||||
|
||||
} /* namespace skiapipeline */
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
79
libs/hwui/pipeline/skia/ATraceMemoryDump.h
Normal file
79
libs/hwui/pipeline/skia/ATraceMemoryDump.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <SkString.h>
|
||||
#include <SkTraceMemoryDump.h>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
namespace skiapipeline {
|
||||
|
||||
class ATraceMemoryDump : public SkTraceMemoryDump {
|
||||
public:
|
||||
ATraceMemoryDump();
|
||||
~ATraceMemoryDump() override {}
|
||||
|
||||
void dumpNumericValue(const char* dumpName, const char* valueName, const char* units,
|
||||
uint64_t value) override;
|
||||
|
||||
void dumpStringValue(const char* dumpName, const char* valueName, const char* value) override;
|
||||
|
||||
LevelOfDetail getRequestedDetails() const override {
|
||||
return SkTraceMemoryDump::kLight_LevelOfDetail;
|
||||
}
|
||||
|
||||
bool shouldDumpWrappedObjects() const override { return false; }
|
||||
|
||||
void setMemoryBacking(const char* dumpName, const char* backingType,
|
||||
const char* backingObjectId) override;
|
||||
|
||||
void setDiscardableMemoryBacking(const char*, const SkDiscardableMemory&) override {}
|
||||
|
||||
void startFrame();
|
||||
|
||||
void logTraces();
|
||||
|
||||
private:
|
||||
std::string mLastDumpName;
|
||||
|
||||
uint64_t mLastDumpValue;
|
||||
|
||||
uint64_t mLastPurgeableDumpValue;
|
||||
|
||||
std::string mCategory;
|
||||
|
||||
struct TraceValue {
|
||||
uint64_t time;
|
||||
uint64_t purgeableTime;
|
||||
};
|
||||
|
||||
// keys are define in sResourceMap
|
||||
std::unordered_map<std::string, TraceValue> mCurrentValues;
|
||||
|
||||
void recordAndResetCountersIfNeeded(const char* dumpName);
|
||||
|
||||
void resetCurrentCounter(const char* dumpName);
|
||||
};
|
||||
|
||||
} /* namespace skiapipeline */
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "renderstate/RenderState.h"
|
||||
|
||||
#include "renderthread/RenderThread.h"
|
||||
#include "GpuMemoryTracker.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
@@ -25,15 +24,10 @@ RenderState::RenderState(renderthread::RenderThread& thread) : mRenderThread(thr
|
||||
mThreadId = pthread_self();
|
||||
}
|
||||
|
||||
void RenderState::onContextCreated() {
|
||||
GpuMemoryTracker::onGpuContextCreated();
|
||||
}
|
||||
|
||||
void RenderState::onContextDestroyed() {
|
||||
for(auto callback : mContextCallbacks) {
|
||||
callback->onContextDestroyed();
|
||||
}
|
||||
GpuMemoryTracker::onGpuContextDestroyed();
|
||||
}
|
||||
|
||||
void RenderState::postDecStrong(VirtualLightRefBase* object) {
|
||||
|
||||
@@ -62,7 +62,6 @@ private:
|
||||
~RenderState() {}
|
||||
|
||||
// Context notifications are only to be triggered by renderthread::RenderThread
|
||||
void onContextCreated();
|
||||
void onContextDestroyed();
|
||||
|
||||
std::set<IGpuContextCallback*> mContextCallbacks;
|
||||
|
||||
@@ -20,10 +20,12 @@
|
||||
#include "Layer.h"
|
||||
#include "Properties.h"
|
||||
#include "RenderThread.h"
|
||||
#include "pipeline/skia/ATraceMemoryDump.h"
|
||||
#include "pipeline/skia/ShaderCache.h"
|
||||
#include "pipeline/skia/SkiaMemoryTracer.h"
|
||||
#include "renderstate/RenderState.h"
|
||||
#include "thread/CommonPool.h"
|
||||
#include <utils/Trace.h>
|
||||
|
||||
#include <GrContextOptions.h>
|
||||
#include <SkExecutor.h>
|
||||
@@ -184,6 +186,18 @@ void CacheManager::dumpMemoryUsage(String8& log, const RenderState* renderState)
|
||||
gpuTracer.logTotals(log);
|
||||
}
|
||||
|
||||
void CacheManager::onFrameCompleted() {
|
||||
if (ATRACE_ENABLED()) {
|
||||
static skiapipeline::ATraceMemoryDump tracer;
|
||||
tracer.startFrame();
|
||||
SkGraphics::DumpMemoryStatistics(&tracer);
|
||||
if (mGrContext) {
|
||||
mGrContext->dumpMemoryStatistics(&tracer);
|
||||
}
|
||||
tracer.logTraces();
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace renderthread */
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
|
||||
size_t getCacheSize() const { return mMaxResourceBytes; }
|
||||
size_t getBackgroundCacheSize() const { return mBackgroundResourceBytes; }
|
||||
void onFrameCompleted();
|
||||
|
||||
private:
|
||||
friend class RenderThread;
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include "CanvasContext.h"
|
||||
|
||||
#include <GpuMemoryTracker.h>
|
||||
#include <apex/window.h>
|
||||
#include <fcntl.h>
|
||||
#include <strings.h>
|
||||
@@ -558,7 +557,7 @@ void CanvasContext::draw() {
|
||||
mJankTracker.finishGpuDraw(*forthBehind);
|
||||
}
|
||||
|
||||
GpuMemoryTracker::onFrameCompleted();
|
||||
mRenderThread.cacheManager().onFrameCompleted();
|
||||
}
|
||||
|
||||
// Called by choreographer to do an RT-driven animation
|
||||
|
||||
@@ -270,7 +270,6 @@ void RenderThread::setGrContext(sk_sp<GrContext> context) {
|
||||
}
|
||||
mGrContext = std::move(context);
|
||||
if (mGrContext) {
|
||||
mRenderState->onContextCreated();
|
||||
DeviceInfo::setMaxTextureSize(mGrContext->maxRenderTargetSize());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
#include <GpuMemoryTracker.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "renderthread/EglManager.h"
|
||||
#include "renderthread/RenderThread.h"
|
||||
#include "tests/common/TestUtils.h"
|
||||
|
||||
#include <utils/StrongPointer.h>
|
||||
|
||||
using namespace android;
|
||||
using namespace android::uirenderer;
|
||||
using namespace android::uirenderer::renderthread;
|
||||
|
||||
class TestGPUObject : public GpuMemoryTracker {
|
||||
public:
|
||||
TestGPUObject() : GpuMemoryTracker(GpuObjectType::Texture) {}
|
||||
|
||||
void changeSize(int newSize) { notifySizeChanged(newSize); }
|
||||
};
|
||||
|
||||
// Other tests may have created a renderthread and EGL context.
|
||||
// This will destroy the EGLContext on RenderThread if it exists so that the
|
||||
// current thread can spoof being a GPU thread
|
||||
static void destroyEglContext() {
|
||||
if (TestUtils::isRenderThreadRunning()) {
|
||||
TestUtils::runOnRenderThread([](RenderThread& thread) { thread.destroyRenderingContext(); });
|
||||
}
|
||||
}
|
||||
|
||||
TEST(GpuMemoryTracker, sizeCheck) {
|
||||
destroyEglContext();
|
||||
|
||||
GpuMemoryTracker::onGpuContextCreated();
|
||||
ASSERT_EQ(0, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
|
||||
ASSERT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture));
|
||||
{
|
||||
TestGPUObject myObj;
|
||||
ASSERT_EQ(1, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture));
|
||||
myObj.changeSize(500);
|
||||
ASSERT_EQ(500, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
|
||||
myObj.changeSize(1000);
|
||||
ASSERT_EQ(1000, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
|
||||
myObj.changeSize(300);
|
||||
ASSERT_EQ(300, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
|
||||
}
|
||||
ASSERT_EQ(0, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
|
||||
ASSERT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture));
|
||||
GpuMemoryTracker::onGpuContextDestroyed();
|
||||
}
|
||||
Reference in New Issue
Block a user