Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "content/common/gpu/gpu_memory_manager.h" |
| 6 | |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 7 | #include <algorithm> |
| 8 | |
| 9 | #include "base/bind.h" |
| 10 | #include "base/command_line.h" |
| 11 | #include "base/debug/trace_event.h" |
Ben Murdoch | 9ab5563 | 2013-07-18 11:57:30 +0100 | [diff] [blame] | 12 | #include "base/message_loop/message_loop.h" |
Ben Murdoch | 58e6fbe | 2013-07-26 10:20:38 +0100 | [diff] [blame] | 13 | #include "base/process/process_handle.h" |
Torne (Richard Coles) | 7d4cd47 | 2013-06-19 11:58:07 +0100 | [diff] [blame] | 14 | #include "base/strings/string_number_conversions.h" |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 15 | #include "content/common/gpu/gpu_channel_manager.h" |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 16 | #include "content/common/gpu/gpu_memory_manager_client.h" |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 17 | #include "content/common/gpu/gpu_memory_tracking.h" |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 18 | #include "content/common/gpu/gpu_memory_uma_stats.h" |
| 19 | #include "content/common/gpu/gpu_messages.h" |
Torne (Richard Coles) | 1e9bf3e | 2013-10-31 11:16:26 +0000 | [diff] [blame] | 20 | #include "gpu/command_buffer/common/gpu_memory_allocation.h" |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 21 | #include "gpu/command_buffer/service/gpu_switches.h" |
| 22 | |
Torne (Richard Coles) | 1e9bf3e | 2013-10-31 11:16:26 +0000 | [diff] [blame] | 23 | using gpu::MemoryAllocation; |
| 24 | |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 25 | namespace content { |
| 26 | namespace { |
| 27 | |
| 28 | const int kDelayedScheduleManageTimeoutMs = 67; |
| 29 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 30 | const uint64 kBytesAllocatedUnmanagedStep = 16 * 1024 * 1024; |
| 31 | |
| 32 | void TrackValueChanged(uint64 old_size, uint64 new_size, uint64* total_size) { |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 33 | DCHECK(new_size > old_size || *total_size >= (old_size - new_size)); |
| 34 | *total_size += (new_size - old_size); |
| 35 | } |
| 36 | |
| 37 | } |
| 38 | |
| 39 | GpuMemoryManager::GpuMemoryManager( |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 40 | GpuChannelManager* channel_manager, |
| 41 | uint64 max_surfaces_with_frontbuffer_soft_limit) |
| 42 | : channel_manager_(channel_manager), |
| 43 | manage_immediate_scheduled_(false), |
Torne (Richard Coles) | f8ee788 | 2014-06-20 14:52:04 +0100 | [diff] [blame] | 44 | disable_schedule_manage_(false), |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 45 | max_surfaces_with_frontbuffer_soft_limit_( |
| 46 | max_surfaces_with_frontbuffer_soft_limit), |
Torne (Richard Coles) | f8ee788 | 2014-06-20 14:52:04 +0100 | [diff] [blame] | 47 | client_hard_limit_bytes_(0), |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 48 | bytes_allocated_managed_current_(0), |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 49 | bytes_allocated_unmanaged_current_(0), |
Torne (Richard Coles) | f8ee788 | 2014-06-20 14:52:04 +0100 | [diff] [blame] | 50 | bytes_allocated_historical_max_(0) |
| 51 | { } |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 52 | |
| 53 | GpuMemoryManager::~GpuMemoryManager() { |
| 54 | DCHECK(tracking_groups_.empty()); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 55 | DCHECK(clients_visible_mru_.empty()); |
| 56 | DCHECK(clients_nonvisible_mru_.empty()); |
| 57 | DCHECK(clients_nonsurface_.empty()); |
| 58 | DCHECK(!bytes_allocated_managed_current_); |
| 59 | DCHECK(!bytes_allocated_unmanaged_current_); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 60 | } |
| 61 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 62 | void GpuMemoryManager::UpdateAvailableGpuMemory() { |
Torne (Richard Coles) | f8ee788 | 2014-06-20 14:52:04 +0100 | [diff] [blame] | 63 | // If the value was overridden on the command line, use the specified value. |
| 64 | static bool client_hard_limit_bytes_overridden = |
Torne (Richard Coles) | 6e8cce6 | 2014-08-19 13:00:08 +0100 | [diff] [blame^] | 65 | base::CommandLine::ForCurrentProcess()->HasSwitch( |
Torne (Richard Coles) | f8ee788 | 2014-06-20 14:52:04 +0100 | [diff] [blame] | 66 | switches::kForceGpuMemAvailableMb); |
| 67 | if (client_hard_limit_bytes_overridden) { |
| 68 | base::StringToUint64( |
Torne (Richard Coles) | 6e8cce6 | 2014-08-19 13:00:08 +0100 | [diff] [blame^] | 69 | base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
Torne (Richard Coles) | f8ee788 | 2014-06-20 14:52:04 +0100 | [diff] [blame] | 70 | switches::kForceGpuMemAvailableMb), |
| 71 | &client_hard_limit_bytes_); |
| 72 | client_hard_limit_bytes_ *= 1024 * 1024; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 73 | return; |
Torne (Richard Coles) | f8ee788 | 2014-06-20 14:52:04 +0100 | [diff] [blame] | 74 | } |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 75 | |
Torne (Richard Coles) | f8ee788 | 2014-06-20 14:52:04 +0100 | [diff] [blame] | 76 | #if defined(OS_ANDROID) |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 77 | // On non-Android, we use an operating system query when possible. |
| 78 | // We do not have a reliable concept of multiple GPUs existing in |
| 79 | // a system, so just be safe and go with the minimum encountered. |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 80 | uint64 bytes_min = 0; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 81 | |
| 82 | // Only use the clients that are visible, because otherwise the set of clients |
| 83 | // we are querying could become extremely large. |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 84 | for (ClientStateList::const_iterator it = clients_visible_mru_.begin(); |
| 85 | it != clients_visible_mru_.end(); |
| 86 | ++it) { |
| 87 | const GpuMemoryManagerClientState* client_state = *it; |
| 88 | if (!client_state->has_surface_) |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 89 | continue; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 90 | if (!client_state->visible_) |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 91 | continue; |
| 92 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 93 | uint64 bytes = 0; |
| 94 | if (client_state->client_->GetTotalGpuMemory(&bytes)) { |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 95 | if (!bytes_min || bytes < bytes_min) |
| 96 | bytes_min = bytes; |
| 97 | } |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 98 | } |
| 99 | |
Torne (Richard Coles) | f8ee788 | 2014-06-20 14:52:04 +0100 | [diff] [blame] | 100 | client_hard_limit_bytes_ = bytes_min; |
| 101 | // Clamp the observed value to a specific range on Android. |
| 102 | client_hard_limit_bytes_ = std::max(client_hard_limit_bytes_, |
| 103 | static_cast<uint64>(16 * 1024 * 1024)); |
| 104 | client_hard_limit_bytes_ = std::min(client_hard_limit_bytes_, |
| 105 | static_cast<uint64>(256 * 1024 * 1024)); |
| 106 | #else |
| 107 | // Ignore what the system said and give all clients the same maximum |
| 108 | // allocation on desktop platforms. |
| 109 | client_hard_limit_bytes_ = 256 * 1024 * 1024; |
| 110 | #endif |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 111 | } |
| 112 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 113 | void GpuMemoryManager::ScheduleManage( |
| 114 | ScheduleManageTime schedule_manage_time) { |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 115 | if (disable_schedule_manage_) |
| 116 | return; |
| 117 | if (manage_immediate_scheduled_) |
| 118 | return; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 119 | if (schedule_manage_time == kScheduleManageNow) { |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 120 | base::MessageLoop::current()->PostTask( |
| 121 | FROM_HERE, base::Bind(&GpuMemoryManager::Manage, AsWeakPtr())); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 122 | manage_immediate_scheduled_ = true; |
| 123 | if (!delayed_manage_callback_.IsCancelled()) |
| 124 | delayed_manage_callback_.Cancel(); |
| 125 | } else { |
| 126 | if (!delayed_manage_callback_.IsCancelled()) |
| 127 | return; |
| 128 | delayed_manage_callback_.Reset(base::Bind(&GpuMemoryManager::Manage, |
| 129 | AsWeakPtr())); |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 130 | base::MessageLoop::current()->PostDelayedTask( |
| 131 | FROM_HERE, |
| 132 | delayed_manage_callback_.callback(), |
| 133 | base::TimeDelta::FromMilliseconds(kDelayedScheduleManageTimeoutMs)); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 134 | } |
| 135 | } |
| 136 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 137 | void GpuMemoryManager::TrackMemoryAllocatedChange( |
| 138 | GpuMemoryTrackingGroup* tracking_group, |
| 139 | uint64 old_size, |
| 140 | uint64 new_size, |
| 141 | gpu::gles2::MemoryTracker::Pool tracking_pool) { |
| 142 | TrackValueChanged(old_size, new_size, &tracking_group->size_); |
| 143 | switch (tracking_pool) { |
| 144 | case gpu::gles2::MemoryTracker::kManaged: |
| 145 | TrackValueChanged(old_size, new_size, &bytes_allocated_managed_current_); |
| 146 | break; |
| 147 | case gpu::gles2::MemoryTracker::kUnmanaged: |
| 148 | TrackValueChanged(old_size, |
| 149 | new_size, |
| 150 | &bytes_allocated_unmanaged_current_); |
| 151 | break; |
| 152 | default: |
| 153 | NOTREACHED(); |
| 154 | break; |
| 155 | } |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 156 | if (new_size != old_size) { |
| 157 | TRACE_COUNTER1("gpu", |
| 158 | "GpuMemoryUsage", |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 159 | GetCurrentUsage()); |
| 160 | } |
| 161 | |
Torne (Richard Coles) | f8ee788 | 2014-06-20 14:52:04 +0100 | [diff] [blame] | 162 | if (GetCurrentUsage() > bytes_allocated_historical_max_ + |
| 163 | kBytesAllocatedUnmanagedStep) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 164 | bytes_allocated_historical_max_ = GetCurrentUsage(); |
| 165 | // If we're blowing into new memory usage territory, spam the browser |
| 166 | // process with the most up-to-date information about our memory usage. |
| 167 | SendUmaStatsToBrowser(); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 168 | } |
| 169 | } |
| 170 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 171 | bool GpuMemoryManager::EnsureGPUMemoryAvailable(uint64 /* size_needed */) { |
| 172 | // TODO: Check if there is enough space. Lose contexts until there is. |
| 173 | return true; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 174 | } |
| 175 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 176 | GpuMemoryManagerClientState* GpuMemoryManager::CreateClientState( |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 177 | GpuMemoryManagerClient* client, |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 178 | bool has_surface, |
| 179 | bool visible) { |
| 180 | TrackingGroupMap::iterator tracking_group_it = |
| 181 | tracking_groups_.find(client->GetMemoryTracker()); |
| 182 | DCHECK(tracking_group_it != tracking_groups_.end()); |
| 183 | GpuMemoryTrackingGroup* tracking_group = tracking_group_it->second; |
| 184 | |
| 185 | GpuMemoryManagerClientState* client_state = new GpuMemoryManagerClientState( |
| 186 | this, client, tracking_group, has_surface, visible); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 187 | AddClientToList(client_state); |
| 188 | ScheduleManage(kScheduleManageNow); |
| 189 | return client_state; |
| 190 | } |
| 191 | |
| 192 | void GpuMemoryManager::OnDestroyClientState( |
| 193 | GpuMemoryManagerClientState* client_state) { |
| 194 | RemoveClientFromList(client_state); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 195 | ScheduleManage(kScheduleManageLater); |
| 196 | } |
| 197 | |
| 198 | void GpuMemoryManager::SetClientStateVisible( |
| 199 | GpuMemoryManagerClientState* client_state, bool visible) { |
| 200 | DCHECK(client_state->has_surface_); |
| 201 | if (client_state->visible_ == visible) |
| 202 | return; |
| 203 | |
| 204 | RemoveClientFromList(client_state); |
| 205 | client_state->visible_ = visible; |
| 206 | AddClientToList(client_state); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 207 | ScheduleManage(visible ? kScheduleManageNow : kScheduleManageLater); |
| 208 | } |
| 209 | |
Torne (Richard Coles) | a3f6a49 | 2013-12-18 16:25:09 +0000 | [diff] [blame] | 210 | uint64 GpuMemoryManager::GetClientMemoryUsage( |
Ben Murdoch | effb81e | 2014-03-31 11:51:25 +0100 | [diff] [blame] | 211 | const GpuMemoryManagerClient* client) const { |
Torne (Richard Coles) | a3f6a49 | 2013-12-18 16:25:09 +0000 | [diff] [blame] | 212 | TrackingGroupMap::const_iterator tracking_group_it = |
| 213 | tracking_groups_.find(client->GetMemoryTracker()); |
| 214 | DCHECK(tracking_group_it != tracking_groups_.end()); |
| 215 | return tracking_group_it->second->GetSize(); |
| 216 | } |
| 217 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 218 | GpuMemoryTrackingGroup* GpuMemoryManager::CreateTrackingGroup( |
| 219 | base::ProcessId pid, gpu::gles2::MemoryTracker* memory_tracker) { |
| 220 | GpuMemoryTrackingGroup* tracking_group = new GpuMemoryTrackingGroup( |
| 221 | pid, memory_tracker, this); |
| 222 | DCHECK(!tracking_groups_.count(tracking_group->GetMemoryTracker())); |
| 223 | tracking_groups_.insert(std::make_pair(tracking_group->GetMemoryTracker(), |
| 224 | tracking_group)); |
| 225 | return tracking_group; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 226 | } |
| 227 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 228 | void GpuMemoryManager::OnDestroyTrackingGroup( |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 229 | GpuMemoryTrackingGroup* tracking_group) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 230 | DCHECK(tracking_groups_.count(tracking_group->GetMemoryTracker())); |
| 231 | tracking_groups_.erase(tracking_group->GetMemoryTracker()); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 232 | } |
| 233 | |
| 234 | void GpuMemoryManager::GetVideoMemoryUsageStats( |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 235 | GPUVideoMemoryUsageStats* video_memory_usage_stats) const { |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 236 | // For each context group, assign its memory usage to its PID |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 237 | video_memory_usage_stats->process_map.clear(); |
| 238 | for (TrackingGroupMap::const_iterator i = |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 239 | tracking_groups_.begin(); i != tracking_groups_.end(); ++i) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 240 | const GpuMemoryTrackingGroup* tracking_group = i->second; |
| 241 | video_memory_usage_stats->process_map[ |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 242 | tracking_group->GetPid()].video_memory += tracking_group->GetSize(); |
| 243 | } |
| 244 | |
| 245 | // Assign the total across all processes in the GPU process |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 246 | video_memory_usage_stats->process_map[ |
| 247 | base::GetCurrentProcId()].video_memory = GetCurrentUsage(); |
| 248 | video_memory_usage_stats->process_map[ |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 249 | base::GetCurrentProcId()].has_duplicates = true; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 250 | |
| 251 | video_memory_usage_stats->bytes_allocated = GetCurrentUsage(); |
| 252 | video_memory_usage_stats->bytes_allocated_historical_max = |
| 253 | bytes_allocated_historical_max_; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 254 | } |
| 255 | |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 256 | void GpuMemoryManager::Manage() { |
| 257 | manage_immediate_scheduled_ = false; |
| 258 | delayed_manage_callback_.Cancel(); |
| 259 | |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 260 | // Update the amount of GPU memory available on the system. |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 261 | UpdateAvailableGpuMemory(); |
| 262 | |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 263 | // Determine which clients are "hibernated" (which determines the |
| 264 | // distribution of frontbuffers and memory among clients that don't have |
| 265 | // surfaces). |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 266 | SetClientsHibernatedState(); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 267 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 268 | // Assign memory allocations to clients that have surfaces. |
| 269 | AssignSurfacesAllocations(); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 270 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 271 | // Assign memory allocations to clients that don't have surfaces. |
| 272 | AssignNonSurfacesAllocations(); |
| 273 | |
| 274 | SendUmaStatsToBrowser(); |
| 275 | } |
| 276 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 277 | void GpuMemoryManager::AssignSurfacesAllocations() { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 278 | // Send that allocation to the clients. |
| 279 | ClientStateList clients = clients_visible_mru_; |
| 280 | clients.insert(clients.end(), |
| 281 | clients_nonvisible_mru_.begin(), |
| 282 | clients_nonvisible_mru_.end()); |
| 283 | for (ClientStateList::const_iterator it = clients.begin(); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 284 | it != clients.end(); |
| 285 | ++it) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 286 | GpuMemoryManagerClientState* client_state = *it; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 287 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 288 | // Populate and send the allocation to the client |
Torne (Richard Coles) | 1e9bf3e | 2013-10-31 11:16:26 +0000 | [diff] [blame] | 289 | MemoryAllocation allocation; |
Torne (Richard Coles) | f8ee788 | 2014-06-20 14:52:04 +0100 | [diff] [blame] | 290 | allocation.bytes_limit_when_visible = client_hard_limit_bytes_; |
| 291 | #if defined(OS_ANDROID) |
| 292 | // On Android, because there is only one visible tab at any time, allow |
| 293 | // that renderer to cache as much as it can. |
| 294 | allocation.priority_cutoff_when_visible = |
| 295 | MemoryAllocation::CUTOFF_ALLOW_EVERYTHING; |
| 296 | #else |
| 297 | // On desktop platforms, instruct the renderers to cache only a smaller |
| 298 | // set, to play nice with other renderers and other applications. If this |
| 299 | // if not done, then the system can become unstable. |
| 300 | // http://crbug.com/145600 (Linux) |
| 301 | // http://crbug.com/141377 (Mac) |
| 302 | allocation.priority_cutoff_when_visible = |
| 303 | MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE; |
| 304 | #endif |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 305 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 306 | client_state->client_->SetMemoryAllocation(allocation); |
Torne (Richard Coles) | 1e9bf3e | 2013-10-31 11:16:26 +0000 | [diff] [blame] | 307 | client_state->client_->SuggestHaveFrontBuffer(!client_state->hibernated_); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 308 | } |
| 309 | } |
| 310 | |
| 311 | void GpuMemoryManager::AssignNonSurfacesAllocations() { |
| 312 | for (ClientStateList::const_iterator it = clients_nonsurface_.begin(); |
| 313 | it != clients_nonsurface_.end(); |
| 314 | ++it) { |
| 315 | GpuMemoryManagerClientState* client_state = *it; |
Torne (Richard Coles) | 1e9bf3e | 2013-10-31 11:16:26 +0000 | [diff] [blame] | 316 | MemoryAllocation allocation; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 317 | |
| 318 | if (!client_state->hibernated_) { |
Torne (Richard Coles) | f8ee788 | 2014-06-20 14:52:04 +0100 | [diff] [blame] | 319 | allocation.bytes_limit_when_visible = client_hard_limit_bytes_; |
Torne (Richard Coles) | 1e9bf3e | 2013-10-31 11:16:26 +0000 | [diff] [blame] | 320 | allocation.priority_cutoff_when_visible = |
| 321 | MemoryAllocation::CUTOFF_ALLOW_EVERYTHING; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 322 | } |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 323 | |
| 324 | client_state->client_->SetMemoryAllocation(allocation); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 325 | } |
| 326 | } |
| 327 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 328 | void GpuMemoryManager::SetClientsHibernatedState() const { |
| 329 | // Re-set all tracking groups as being hibernated. |
| 330 | for (TrackingGroupMap::const_iterator it = tracking_groups_.begin(); |
| 331 | it != tracking_groups_.end(); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 332 | ++it) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 333 | GpuMemoryTrackingGroup* tracking_group = it->second; |
| 334 | tracking_group->hibernated_ = true; |
| 335 | } |
| 336 | // All clients with surfaces that are visible are non-hibernated. |
| 337 | uint64 non_hibernated_clients = 0; |
| 338 | for (ClientStateList::const_iterator it = clients_visible_mru_.begin(); |
| 339 | it != clients_visible_mru_.end(); |
| 340 | ++it) { |
| 341 | GpuMemoryManagerClientState* client_state = *it; |
| 342 | client_state->hibernated_ = false; |
| 343 | client_state->tracking_group_->hibernated_ = false; |
| 344 | non_hibernated_clients++; |
| 345 | } |
| 346 | // Then an additional few clients with surfaces are non-hibernated too, up to |
| 347 | // a fixed limit. |
| 348 | for (ClientStateList::const_iterator it = clients_nonvisible_mru_.begin(); |
| 349 | it != clients_nonvisible_mru_.end(); |
| 350 | ++it) { |
| 351 | GpuMemoryManagerClientState* client_state = *it; |
| 352 | if (non_hibernated_clients < max_surfaces_with_frontbuffer_soft_limit_) { |
| 353 | client_state->hibernated_ = false; |
| 354 | client_state->tracking_group_->hibernated_ = false; |
| 355 | non_hibernated_clients++; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 356 | } else { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 357 | client_state->hibernated_ = true; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 358 | } |
| 359 | } |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 360 | // Clients that don't have surfaces are non-hibernated if they are |
| 361 | // in a GL share group with a non-hibernated surface. |
| 362 | for (ClientStateList::const_iterator it = clients_nonsurface_.begin(); |
| 363 | it != clients_nonsurface_.end(); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 364 | ++it) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 365 | GpuMemoryManagerClientState* client_state = *it; |
| 366 | client_state->hibernated_ = client_state->tracking_group_->hibernated_; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 367 | } |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 368 | } |
| 369 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 370 | void GpuMemoryManager::SendUmaStatsToBrowser() { |
| 371 | if (!channel_manager_) |
| 372 | return; |
| 373 | GPUMemoryUmaStats params; |
| 374 | params.bytes_allocated_current = GetCurrentUsage(); |
| 375 | params.bytes_allocated_max = bytes_allocated_historical_max_; |
Torne (Richard Coles) | f8ee788 | 2014-06-20 14:52:04 +0100 | [diff] [blame] | 376 | params.bytes_limit = client_hard_limit_bytes_; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 377 | params.client_count = clients_visible_mru_.size() + |
| 378 | clients_nonvisible_mru_.size() + |
| 379 | clients_nonsurface_.size(); |
| 380 | params.context_group_count = tracking_groups_.size(); |
| 381 | channel_manager_->Send(new GpuHostMsg_GpuMemoryUmaStats(params)); |
| 382 | } |
| 383 | |
| 384 | GpuMemoryManager::ClientStateList* GpuMemoryManager::GetClientList( |
| 385 | GpuMemoryManagerClientState* client_state) { |
| 386 | if (client_state->has_surface_) { |
| 387 | if (client_state->visible_) |
| 388 | return &clients_visible_mru_; |
| 389 | else |
| 390 | return &clients_nonvisible_mru_; |
| 391 | } |
| 392 | return &clients_nonsurface_; |
| 393 | } |
| 394 | |
| 395 | void GpuMemoryManager::AddClientToList( |
| 396 | GpuMemoryManagerClientState* client_state) { |
| 397 | DCHECK(!client_state->list_iterator_valid_); |
| 398 | ClientStateList* client_list = GetClientList(client_state); |
| 399 | client_state->list_iterator_ = client_list->insert( |
| 400 | client_list->begin(), client_state); |
| 401 | client_state->list_iterator_valid_ = true; |
| 402 | } |
| 403 | |
| 404 | void GpuMemoryManager::RemoveClientFromList( |
| 405 | GpuMemoryManagerClientState* client_state) { |
| 406 | DCHECK(client_state->list_iterator_valid_); |
| 407 | ClientStateList* client_list = GetClientList(client_state); |
| 408 | client_list->erase(client_state->list_iterator_); |
| 409 | client_state->list_iterator_valid_ = false; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 410 | } |
| 411 | |
| 412 | } // namespace content |