Index: content/common/gpu/gpu_memory_manager.cc |
diff --git a/content/common/gpu/gpu_memory_manager.cc b/content/common/gpu/gpu_memory_manager.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5bed2c420f34f378ab08216bb6e6d0ee3f0801b7 |
--- /dev/null |
+++ b/content/common/gpu/gpu_memory_manager.cc |
@@ -0,0 +1,130 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/common/gpu/gpu_memory_manager.h" |
+ |
+#if defined(ENABLE_GPU) |
+ |
+#include <set> |
+#include <algorithm> |
+ |
+#include "base/bind.h" |
+#include "base/message_loop.h" |
+#include "content/common/gpu/gpu_command_buffer_stub.h" |
+#include "content/common/gpu/gpu_memory_allocation.h" |
+ |
+const size_t GpuMemoryManager::kDefaultMaxSurfacesWithFrontbufferSoftLimit = 8; |
+ |
+namespace { |
+ |
+// These are predefined values (in bytes) for |
+// GpuMemoryAllocation::gpuResourceSizeInBytes. Currently, the value is only |
+// used to check if it is 0 or non-0. In the future, these values will not |
+// come from constants, but rather will be distributed dynamically. |
+const uint32 kResourceSizeNonHibernatedTab = 1; |
+const uint32 kResourceSizeHibernatedTab = 0; |
+ |
+// Set up three allocation values for the three possible stub states |
+const GpuMemoryAllocation all_buffers_allocation( |
+ kResourceSizeNonHibernatedTab, true, true); |
+const GpuMemoryAllocation front_buffers_allocation( |
+ kResourceSizeNonHibernatedTab, true, false); |
+const GpuMemoryAllocation no_buffers_allocation( |
+ kResourceSizeHibernatedTab, false, false); |
+ |
+} |
+ |
+GpuMemoryManager::GpuMemoryManager(GpuMemoryManagerClient* client, |
+ size_t max_surfaces_with_frontbuffer_soft_limit) |
+ : client_(client), |
+ manage_scheduled_(false), |
+ max_surfaces_with_frontbuffer_soft_limit_( |
+ max_surfaces_with_frontbuffer_soft_limit), |
+ weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
+} |
+ |
+GpuMemoryManager::~GpuMemoryManager() { |
+} |
+ |
+bool GpuMemoryManager::StubWithSurfaceComparator::operator()( |
+ GpuCommandBufferStubBase* lhs, |
+ GpuCommandBufferStubBase* rhs) { |
+ DCHECK(lhs->has_surface_state() && rhs->has_surface_state()); |
+ const GpuCommandBufferStubBase::SurfaceState& lhs_ss = lhs->surface_state(); |
+ const GpuCommandBufferStubBase::SurfaceState& rhs_ss = rhs->surface_state(); |
+ if (lhs_ss.visible) |
+ return !rhs_ss.visible || (lhs_ss.last_used_time > rhs_ss.last_used_time); |
+ else |
+ return !rhs_ss.visible && (lhs_ss.last_used_time > rhs_ss.last_used_time); |
+}; |
+ |
+void GpuMemoryManager::ScheduleManage() { |
+ if (manage_scheduled_) |
+ return; |
+ MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&GpuMemoryManager::Manage, weak_factory_.GetWeakPtr())); |
+ manage_scheduled_ = true; |
+} |
+ |
+// The current Manage algorithm simply classifies contexts (stubs) into |
+// "foreground", "background", or "hibernated" categories. |
+// For each of these three categories, there are predefined memory allocation |
+// limits and front/backbuffer states. |
+// |
+// Stubs may or may not have a surfaces, and the rules are different for each. |
+// |
+// The rules for categorizing contexts with a surface are: |
+// 1. Foreground: All visible surfaces. |
+// * Must have both front and back buffer. |
+// |
+// 2. Background: Non visible surfaces, which have not surpassed the |
+// max_surfaces_with_frontbuffer_soft_limit_ limit. |
+// * Will have only a frontbuffer. |
+// |
+// 3. Hibernated: Non visible surfaces, which have surpassed the |
+// max_surfaces_with_frontbuffer_soft_limit_ limit. |
+// * Will not have either buffer. |
+void GpuMemoryManager::Manage() { |
+ manage_scheduled_ = false; |
+ |
+ // Create stub lists by separating out the two types received from client |
+ std::vector<GpuCommandBufferStubBase*> stubs_with_surface; |
+ { |
+ std::vector<GpuCommandBufferStubBase*> stubs; |
+ client_->AppendAllCommandBufferStubs(stubs); |
+ |
+ for (std::vector<GpuCommandBufferStubBase*>::iterator it = stubs.begin(); |
+ it != stubs.end(); ++it) { |
+ GpuCommandBufferStubBase* stub = *it; |
+ if (stub->has_surface_state()) |
+ stubs_with_surface.push_back(stub); |
+ } |
+ } |
+ |
+ // Sort stubs with surface into {visibility,last_used_time} order using |
+ // custom comparator |
+ std::sort(stubs_with_surface.begin(), stubs_with_surface.end(), |
+ StubWithSurfaceComparator()); |
+ |
+ // Separate stubs with surfaces into three sets and send memory allocation |
+ std::set<int32> all_buffers, front_buffers, no_buffers; |
+ |
+ for (size_t i = 0; i < stubs_with_surface.size(); ++i) { |
+ GpuCommandBufferStubBase* stub = stubs_with_surface[i]; |
+ DCHECK(stub->has_surface_state()); |
+ if (stub->surface_state().visible) { |
+ all_buffers.insert(stub->surface_state().surface_id); |
+ stub->SendMemoryAllocationToProxy(all_buffers_allocation); |
+ } else if (i < max_surfaces_with_frontbuffer_soft_limit_) { |
+ front_buffers.insert(stub->surface_state().surface_id); |
+ stub->SendMemoryAllocationToProxy(front_buffers_allocation); |
+ } else { |
+ no_buffers.insert(stub->surface_state().surface_id); |
+ stub->SendMemoryAllocationToProxy(no_buffers_allocation); |
+ } |
+ } |
+} |
+ |
+#endif |