Commit bee73f5d authored by ccameron@chromium.org's avatar ccameron@chromium.org

Add a flag to specify the total amount of memory which may be allocated to GPU resources.

Change constants in GpuMemoryManager to helper functions (and variables).

This is towards (1) automated testing of the GPU memory manager and (2) getting actual vidmem values.

BUG=132994


Review URL: https://chromiumcodereview.appspot.com/10823092

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149149 0039d316-1c4b-4281-b951-d872f2087c98
parent 3f869667
......@@ -9,10 +9,13 @@
#include <algorithm>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/message_loop.h"
#include "base/string_number_conversions.h"
#include "content/common/gpu/gpu_command_buffer_stub.h"
#include "content/common/gpu/gpu_memory_allocation.h"
#include "gpu/command_buffer/service/gpu_switches.h"
namespace {
......@@ -29,25 +32,6 @@ bool IsInSameContextShareGroupAsAnyOf(
return false;
}
#if defined(OS_ANDROID)
size_t CalculateBonusMemoryAllocationBasedOnSize(gfx::Size size) {
const int viewportMultiplier = 16;
const unsigned int componentsPerPixel = 4; // GraphicsContext3D::RGBA
const unsigned int bytesPerComponent = 1; // sizeof(GC3Dubyte)
if (size.IsEmpty())
return 0;
size_t limit = viewportMultiplier * size.width() * size.height() *
componentsPerPixel * bytesPerComponent;
if (limit < GpuMemoryManager::kMinimumAllocationForTab)
limit = GpuMemoryManager::kMinimumAllocationForTab;
else if (limit > GpuMemoryManager::kMaximumAllocationForTabs)
limit = GpuMemoryManager::kMaximumAllocationForTabs;
return limit - GpuMemoryManager::kMinimumAllocationForTab;
}
#endif
void AssignMemoryAllocations(
GpuMemoryManager::StubMemoryStatMap* stub_memory_stats,
const std::vector<GpuCommandBufferStubBase*>& stubs,
......@@ -65,14 +49,46 @@ void AssignMemoryAllocations(
}
size_t GpuMemoryManager::CalculateBonusMemoryAllocationBasedOnSize(
gfx::Size size) const {
const int kViewportMultiplier = 16;
const unsigned int kComponentsPerPixel = 4; // GraphicsContext3D::RGBA
const unsigned int kBytesPerComponent = 1; // sizeof(GC3Dubyte)
if (size.IsEmpty())
return 0;
size_t limit = kViewportMultiplier * size.width() * size.height() *
kComponentsPerPixel * kBytesPerComponent;
if (limit < GetMinimumTabAllocation())
limit = GetMinimumTabAllocation();
else if (limit > GetAvailableGpuMemory())
limit = GetAvailableGpuMemory();
return limit - GetMinimumTabAllocation();
}
GpuMemoryManager::GpuMemoryManager(GpuMemoryManagerClient* client,
size_t max_surfaces_with_frontbuffer_soft_limit)
: client_(client),
manage_immediate_scheduled_(false),
max_surfaces_with_frontbuffer_soft_limit_(
max_surfaces_with_frontbuffer_soft_limit),
bytes_available_gpu_memory_(0),
bytes_allocated_current_(0),
bytes_allocated_historical_max_(0) {
CommandLine* command_line = CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kForceGpuMemAvailableMb)) {
base::StringToSizeT(
command_line->GetSwitchValueASCII(switches::kForceGpuMemAvailableMb),
&bytes_available_gpu_memory_);
bytes_available_gpu_memory_ *= 1024 * 1024;
} else {
#if defined(OS_ANDROID)
bytes_available_gpu_memory_ = 64 * 1024 * 1024;
#else
bytes_available_gpu_memory_ = 448 * 1024 * 1024;
#endif
}
}
GpuMemoryManager::~GpuMemoryManager() {
......@@ -112,11 +128,6 @@ void GpuMemoryManager::ScheduleManage(bool immediate) {
}
}
size_t GpuMemoryManager::GetAvailableGpuMemory() const {
// TODO(mmocny): Implement this with real system figures.
return kMaximumAllocationForTabs;
}
void GpuMemoryManager::TrackMemoryAllocatedChange(size_t old_size,
size_t new_size)
{
......@@ -124,8 +135,7 @@ void GpuMemoryManager::TrackMemoryAllocatedChange(size_t old_size,
size_t delta = old_size - new_size;
DCHECK(bytes_allocated_current_ >= delta);
bytes_allocated_current_ -= delta;
}
else {
} else {
size_t delta = new_size - old_size;
bytes_allocated_current_ += delta;
if (bytes_allocated_current_ > bytes_allocated_historical_max_) {
......@@ -241,11 +251,11 @@ void GpuMemoryManager::Manage() {
size_t num_stubs_need_mem = stubs_with_surface_foreground.size() +
stubs_without_surface_foreground.size() +
stubs_without_surface_background.size();
size_t base_allocation_size = kMinimumAllocationForTab * num_stubs_need_mem;
if (base_allocation_size < kMaximumAllocationForTabs &&
size_t base_allocation_size = GetMinimumTabAllocation() * num_stubs_need_mem;
if (base_allocation_size < GetAvailableGpuMemory() &&
!stubs_with_surface_foreground.empty())
bonus_allocation = (kMaximumAllocationForTabs - base_allocation_size) /
stubs_with_surface_foreground.size();
bonus_allocation = (GetAvailableGpuMemory() - base_allocation_size) /
stubs_with_surface_foreground.size();
#else
// On android, calculate bonus allocation based on surface size.
if (!stubs_with_surface_foreground.empty())
......@@ -259,7 +269,7 @@ void GpuMemoryManager::Manage() {
AssignMemoryAllocations(
&stub_memory_stats_for_last_manage_,
stubs_with_surface_foreground,
GpuMemoryAllocation(kMinimumAllocationForTab + bonus_allocation,
GpuMemoryAllocation(GetMinimumTabAllocation() + bonus_allocation,
GpuMemoryAllocation::kHasFrontbuffer |
GpuMemoryAllocation::kHasBackbuffer),
true);
......@@ -279,14 +289,14 @@ void GpuMemoryManager::Manage() {
AssignMemoryAllocations(
&stub_memory_stats_for_last_manage_,
stubs_without_surface_foreground,
GpuMemoryAllocation(kMinimumAllocationForTab,
GpuMemoryAllocation(GetMinimumTabAllocation(),
GpuMemoryAllocation::kHasNoBuffers),
true);
AssignMemoryAllocations(
&stub_memory_stats_for_last_manage_,
stubs_without_surface_background,
GpuMemoryAllocation(kMinimumAllocationForTab,
GpuMemoryAllocation(GetMinimumTabAllocation(),
GpuMemoryAllocation::kHasNoBuffers),
false);
......@@ -295,14 +305,6 @@ void GpuMemoryManager::Manage() {
stubs_without_surface_hibernated,
GpuMemoryAllocation(0, GpuMemoryAllocation::kHasNoBuffers),
false);
size_t assigned_allocation_sum = 0;
for (StubMemoryStatMap::iterator it =
stub_memory_stats_for_last_manage_.begin();
it != stub_memory_stats_for_last_manage_.end();
++it) {
assigned_allocation_sum += it->second.allocation.gpu_resource_size_in_bytes;
}
}
#endif
......@@ -15,6 +15,7 @@
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
#include "content/common/gpu/gpu_memory_allocation.h"
#include "ui/gfx/size.h"
class GpuCommandBufferStubBase;
......@@ -42,22 +43,6 @@ class CONTENT_EXPORT GpuMemoryManager :
public:
enum { kDefaultMaxSurfacesWithFrontbufferSoftLimit = 8 };
// These are predefined values (in bytes) for
// GpuMemoryAllocation::gpuResourceSizeInBytes.
// Maximum Allocation for all tabs is a soft limit that can be exceeded
// during the time it takes for renderers to respect new allocations,
// including when switching tabs or opening a new window.
// To alleviate some pressure, we decrease our desired limit by "one tabs'
// worth" of memory.
enum {
#if defined(OS_ANDROID)
kMinimumAllocationForTab = 32 * 1024 * 1024,
kMaximumAllocationForTabs = 64 * 1024 * 1024,
#else
kMinimumAllocationForTab = 64 * 1024 * 1024,
kMaximumAllocationForTabs = 512 * 1024 * 1024 - kMinimumAllocationForTab,
#endif
};
// StubMemoryStat is used to store memory-allocation-related information about
// a GpuCommandBufferStubBase for some time point.
......@@ -88,19 +73,29 @@ class CONTENT_EXPORT GpuMemoryManager :
return stub_memory_stats_for_last_manage_;
}
// Tries to estimate the total available gpu memory for use by
// GpuMemoryManager. Ideally should consider other system applications and
// other internal but non GpuMemoryManager managed sources, etc.
size_t GetAvailableGpuMemory() const;
// Track a change in memory allocated by any context
void TrackMemoryAllocatedChange(size_t old_size, size_t new_size);
private:
friend class GpuMemoryManagerTest;
void Manage();
size_t CalculateBonusMemoryAllocationBasedOnSize(gfx::Size size) const;
size_t GetAvailableGpuMemory() const {
return bytes_available_gpu_memory_;
}
// The minimum non-zero amount of memory that a tab may be assigned
size_t GetMinimumTabAllocation() const {
#if defined(OS_ANDROID)
return 32 * 1024 * 1024;
#else
return 64 * 1024 * 1024;
#endif
}
class CONTENT_EXPORT StubWithSurfaceComparator {
public:
bool operator()(GpuCommandBufferStubBase* lhs,
......@@ -116,6 +111,9 @@ class CONTENT_EXPORT GpuMemoryManager :
StubMemoryStatMap stub_memory_stats_for_last_manage_;
// The maximum amount of memory that may be allocated for GPU resources
size_t bytes_available_gpu_memory_;
// The current total memory usage, and historical maximum memory usage
size_t bytes_allocated_current_;
size_t bytes_allocated_historical_max_;
......
......@@ -114,40 +114,37 @@ class GpuMemoryManagerTest : public testing::Test {
return GpuMemoryManager::StubWithSurfaceComparator()(lhs, rhs);
}
static bool IsAllocationForegroundForSurfaceYes(
bool IsAllocationForegroundForSurfaceYes(
const GpuMemoryAllocation& alloc) {
return alloc.suggest_have_frontbuffer &&
alloc.suggest_have_backbuffer &&
alloc.gpu_resource_size_in_bytes >=
GpuMemoryManager::kMinimumAllocationForTab;
alloc.gpu_resource_size_in_bytes >= GetMinimumTabAllocation();
}
static bool IsAllocationBackgroundForSurfaceYes(
bool IsAllocationBackgroundForSurfaceYes(
const GpuMemoryAllocation& alloc) {
return alloc.suggest_have_frontbuffer &&
!alloc.suggest_have_backbuffer &&
alloc.gpu_resource_size_in_bytes == 0;
}
static bool IsAllocationHibernatedForSurfaceYes(
bool IsAllocationHibernatedForSurfaceYes(
const GpuMemoryAllocation& alloc) {
return !alloc.suggest_have_frontbuffer &&
!alloc.suggest_have_backbuffer &&
alloc.gpu_resource_size_in_bytes == 0;
}
static bool IsAllocationForegroundForSurfaceNo(
bool IsAllocationForegroundForSurfaceNo(
const GpuMemoryAllocation& alloc) {
return !alloc.suggest_have_frontbuffer &&
!alloc.suggest_have_backbuffer &&
alloc.gpu_resource_size_in_bytes ==
GpuMemoryManager::kMinimumAllocationForTab;
alloc.gpu_resource_size_in_bytes == GetMinimumTabAllocation();
}
static bool IsAllocationBackgroundForSurfaceNo(
bool IsAllocationBackgroundForSurfaceNo(
const GpuMemoryAllocation& alloc) {
return !alloc.suggest_have_frontbuffer &&
!alloc.suggest_have_backbuffer &&
alloc.gpu_resource_size_in_bytes ==
GpuMemoryManager::kMinimumAllocationForTab;
alloc.gpu_resource_size_in_bytes == GetMinimumTabAllocation();
}
static bool IsAllocationHibernatedForSurfaceNo(
bool IsAllocationHibernatedForSurfaceNo(
const GpuMemoryAllocation& alloc) {
return !alloc.suggest_have_frontbuffer &&
!alloc.suggest_have_backbuffer &&
......@@ -158,6 +155,14 @@ class GpuMemoryManagerTest : public testing::Test {
memory_manager_.Manage();
}
size_t GetAvailableGpuMemory() {
return memory_manager_.GetAvailableGpuMemory();
}
size_t GetMinimumTabAllocation() {
return memory_manager_.GetMinimumTabAllocation();
}
base::TimeTicks older_, newer_, newest_;
FakeClient client_;
GpuMemoryManager memory_manager_;
......@@ -481,12 +486,11 @@ TEST_F(GpuMemoryManagerTest, TestManageChangingImportanceShareGroup) {
// Test GpuMemoryAllocation memory allocation bonuses:
// When the number of visible tabs is small, each tab should get a
// gpu_resource_size_in_bytes allocation value that is greater than
// kMinimumAllocationForTab, and when the number of tabs is large, each should
// get exactly kMinimumAllocationForTab and not less.
// GetMinimumTabAllocation(), and when the number of tabs is large, each should
// get exactly GetMinimumTabAllocation() and not less.
TEST_F(GpuMemoryManagerTest, TestForegroundStubsGetBonusAllocation) {
size_t max_stubs_before_no_bonus =
GpuMemoryManager::kMaximumAllocationForTabs /
(GpuMemoryManager::kMinimumAllocationForTab + 1);
GetAvailableGpuMemory() / (GetMinimumTabAllocation() + 1);
std::vector<FakeCommandBufferStub> stubs;
for (size_t i = 0; i < max_stubs_before_no_bonus; ++i) {
......@@ -501,7 +505,7 @@ TEST_F(GpuMemoryManagerTest, TestForegroundStubsGetBonusAllocation) {
for (size_t i = 0; i < stubs.size(); ++i) {
EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stubs[i].allocation_));
EXPECT_GT(stubs[i].allocation_.gpu_resource_size_in_bytes,
static_cast<size_t>(GpuMemoryManager::kMinimumAllocationForTab));
static_cast<size_t>(GetMinimumTabAllocation()));
}
FakeCommandBufferStub extra_stub(GenerateUniqueSurfaceId(), true, older_);
......@@ -511,7 +515,7 @@ TEST_F(GpuMemoryManagerTest, TestForegroundStubsGetBonusAllocation) {
for (size_t i = 0; i < stubs.size(); ++i) {
EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stubs[i].allocation_));
EXPECT_EQ(stubs[i].allocation_.gpu_resource_size_in_bytes,
GpuMemoryManager::kMinimumAllocationForTab);
GetMinimumTabAllocation());
}
}
#else
......@@ -527,12 +531,12 @@ TEST_F(GpuMemoryManagerTest, TestForegroundStubsGetBonusAllocationAndroid) {
Manage();
EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub.allocation_));
EXPECT_EQ(stub.allocation_.gpu_resource_size_in_bytes,
GpuMemoryManager::kMinimumAllocationForTab);
GetMinimumTabAllocation());
// Keep increasing size, making sure allocation is always increasing
// Until it finally reaches the maximum.
while (stub.allocation_.gpu_resource_size_in_bytes <
GpuMemoryManager::kMaximumAllocationForTabs) {
GetAvailableGpuMemory()) {
size_t previous_allocation = stub.allocation_.gpu_resource_size_in_bytes;
stub.size_ = stub.size_.Scale(1, 2);
......@@ -540,9 +544,9 @@ TEST_F(GpuMemoryManagerTest, TestForegroundStubsGetBonusAllocationAndroid) {
Manage();
EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub.allocation_));
EXPECT_GE(stub.allocation_.gpu_resource_size_in_bytes,
GpuMemoryManager::kMinimumAllocationForTab);
GetMinimumTabAllocation());
EXPECT_LE(stub.allocation_.gpu_resource_size_in_bytes,
GpuMemoryManager::kMaximumAllocationForTabs);
GetAvailableGpuMemory());
EXPECT_GE(stub.allocation_.gpu_resource_size_in_bytes,
previous_allocation);
}
......@@ -553,7 +557,7 @@ TEST_F(GpuMemoryManagerTest, TestForegroundStubsGetBonusAllocationAndroid) {
Manage();
EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub.allocation_));
EXPECT_EQ(stub.allocation_.gpu_resource_size_in_bytes,
GpuMemoryManager::kMaximumAllocationForTabs);
GetAvailableGpuMemory());
}
#endif
......
......@@ -37,6 +37,9 @@ const char kEnforceGLMinimums[] = "enforce-gl-minimums";
// affected systems.
const char kForceGLFinishWorkaround[] = "force-glfinish-workaround";
// Sets the total amount of memory that may be allocated for GPU resources
const char kForceGpuMemAvailableMb[] = "force-gpu-mem-available-mb";
// Sets the maximum size of the in-memory gpu program cache, in kb
const char kGpuProgramCacheSizeKb[] = "gpu-program-cache-size-kb";
......@@ -52,6 +55,7 @@ const char* kGpuSwitches[] = {
kDisableGpuProgramCache,
kEnforceGLMinimums,
kForceGLFinishWorkaround,
kForceGpuMemAvailableMb,
kGpuProgramCacheSizeKb,
kTraceGL,
};
......
......@@ -20,6 +20,7 @@ GPU_EXPORT extern const char kEnableGPUDebugging[];
GPU_EXPORT extern const char kDisableGpuProgramCache[];
GPU_EXPORT extern const char kEnforceGLMinimums[];
GPU_EXPORT extern const char kForceGLFinishWorkaround[];
GPU_EXPORT extern const char kForceGpuMemAvailableMb[];
GPU_EXPORT extern const char kGpuProgramCacheSizeKb[];
GPU_EXPORT extern const char kTraceGL[];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment