Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 7 #if defined(ENABLE_GPU) | |
| 8 | |
| 9 #include "content/common/gpu/gpu_channel_manager.h" | |
| 10 #include "content/common/gpu/gpu_channel.h" | |
| 11 #include "content/common/gpu/gpu_command_buffer_stub.h" | |
| 12 | |
| 13 #include <vector> | |
| 14 | |
| 15 //////////////////////////////////////////////////////////////////////////////// | |
| 16 // Local helpers | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 /* | |
| 21 * A RenderWidgetDescriptor is used to combine the information various stubs | |
| 22 * receive, in order to best infer the RenderWidget's current state. | |
| 23 */ | |
| 24 class RenderWidgetDescriptor { | |
| 25 public: | |
| 26 RenderWidgetDescriptor(int render_widget_id, | |
|
nduca
2012/01/27 10:10:13
This comment applies to this entire patch. but we
| |
| 27 bool visible, | |
| 28 int64 last_used_time, | |
| 29 GpuCommandBufferStub* stub) | |
| 30 : render_widget_id_(render_widget_id) | |
| 31 , visible_(visible) | |
| 32 , last_used_time_(last_used_time) | |
| 33 , stubs_(1,stub) { | |
| 34 } | |
| 35 | |
| 36 public: | |
| 37 int render_widget_id() const { return render_widget_id_; } | |
| 38 bool visible() const { return visible_; } | |
| 39 int64 last_used_time() const { return last_used_time_; } | |
| 40 std::vector<GpuCommandBufferStub*> const& stubs() const { return stubs_; } | |
| 41 | |
| 42 // This is a helper function to learn from another descriptor for the same | |
|
nduca
2012/01/27 10:10:13
??? when do you merge? This feels like some seriou
mmocny
2012/01/27 19:51:33
This is a convenience function which I will move o
| |
| 43 // RenderWidget, thus creating a single more accurate one. | |
| 44 void merge(RenderWidgetDescriptor const& other) { | |
| 45 DCHECK(render_widget_id_ == other.render_widget_id_); | |
| 46 // Check if this RWD has staler data than other: | |
| 47 if ((last_used_time_ == GpuCommandBufferStub::kUnknownLastUsedTime) || | |
| 48 (other.last_used_time_ != GpuCommandBufferStub::kUnknownLastUsedTime && | |
| 49 last_used_time_ < other.last_used_time_)) { | |
| 50 visible_ = other.visible_; | |
| 51 last_used_time_ = other.last_used_time_; | |
| 52 } | |
| 53 // Either way, merge stubs | |
| 54 stubs_.insert(stubs_.end(), other.stubs_.begin(), other.stubs_.end()); | |
| 55 // TODO(mmocny): DCHECK(confirm-no-duplicates) | |
| 56 // This is currently certain to be true, but should state assumptions | |
| 57 // since this assumption isn't enforced | |
| 58 } | |
| 59 | |
| 60 private: | |
| 61 int render_widget_id_; | |
| 62 | |
| 63 bool visible_; | |
| 64 int64 last_used_time_; | |
| 65 | |
| 66 std::vector<GpuCommandBufferStub*> stubs_; | |
| 67 }; | |
| 68 | |
| 69 /* | |
| 70 * Used to sort RenderWidgetDescriptors into most-to-least "important" order | |
| 71 */ | |
| 72 struct RenderWidgetDescriptorSorter { | |
| 73 bool operator()(RenderWidgetDescriptor* lhs, RenderWidgetDescriptor* rhs) { | |
| 74 if (lhs->visible() != rhs->visible()) // Visible RWD first | |
| 75 return lhs->visible(); | |
| 76 else if (lhs->visible()) // Use id as tiebreaker when both are visible | |
| 77 return lhs->render_widget_id() < rhs->render_widget_id(); | |
| 78 | |
| 79 DCHECK(lhs->last_used_time() != GpuCommandBufferStub::kUnknownLastUsedTime); | |
| 80 DCHECK(rhs->last_used_time() != GpuCommandBufferStub::kUnknownLastUsedTime); | |
| 81 // Last-used-time order for non visible ones | |
| 82 return lhs->last_used_time() > rhs->last_used_time(); | |
| 83 } | |
| 84 }; | |
|
nduca
2012/01/27 10:10:13
Unit tests, or file a bug and write unit tests aft
mmocny
2012/01/27 19:51:33
This should be easy to test.
On 2012/01/27 10:10:
| |
| 85 | |
| 86 /* | |
| 87 * GetGpuCommandBufferStubs | |
| 88 */ | |
| 89 std::vector<GpuCommandBufferStub*> GetGpuCommandBufferStubs( | |
| 90 GpuChannelManager* channel_manager) { | |
| 91 std::vector<GpuCommandBufferStub*> ret; | |
| 92 | |
| 93 std::vector<GpuChannel*> channels = channel_manager->GetChannels(); | |
| 94 | |
| 95 for (std::vector<GpuChannel*>::const_iterator channel_it = channels.begin(); | |
| 96 channel_it != channels.end(); ++channel_it ) { | |
| 97 GpuChannel* channel = *channel_it; | |
| 98 std::vector<GpuCommandBufferStub*> stubs = channel->GetCommandBuffers(); | |
| 99 ret.insert(ret.end(), stubs.begin(), stubs.end()); | |
| 100 } | |
| 101 return ret; | |
| 102 } | |
| 103 | |
| 104 /* | |
| 105 * ComputeRenderWidgetDescriptorsFromStubs | |
| 106 */ | |
| 107 std::vector<RenderWidgetDescriptor*> ComputeRenderWidgetDescriptorsFromStubs( | |
|
nduca
2012/01/27 10:10:13
Why are you doing this? Why not just get a vector
mmocny
2012/01/27 19:51:33
I promise there was a method to this madness but I
| |
| 108 std::vector<GpuCommandBufferStub*> stubs) { | |
| 109 std::vector<RenderWidgetDescriptor*> ret; | |
| 110 | |
| 111 for (std::vector<GpuCommandBufferStub*>::iterator gcbs_it = stubs.begin(); | |
| 112 gcbs_it != stubs.end(); ++gcbs_it) { | |
| 113 GpuCommandBufferStub* stub = *gcbs_it; | |
| 114 std::vector<int> render_widget_ids = stub->render_widget_ids(); | |
| 115 | |
| 116 for (std::vector<int>::iterator rwids_it = render_widget_ids.begin(); | |
| 117 rwids_it != render_widget_ids.end(); ++rwids_it) { | |
| 118 RenderWidgetDescriptor* rwd = new RenderWidgetDescriptor(*rwids_it, | |
| 119 stub->visible(), stub->last_used_time(), stub); | |
| 120 | |
| 121 // Try to find existing Render Widget | |
| 122 for (std::vector<RenderWidgetDescriptor*>::iterator rwds_it = ret.begin(); | |
| 123 rwds_it != ret.end(); ++rwds_it) { | |
| 124 if ((*rwds_it)->render_widget_id() == *rwids_it) { | |
| 125 (*rwds_it)->merge(*rwd); | |
| 126 rwd = NULL; | |
| 127 break; | |
| 128 } | |
| 129 } | |
| 130 if (rwd) | |
| 131 ret.push_back(rwd); | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 return ret; | |
| 136 } | |
| 137 | |
| 138 } | |
| 139 | |
| 140 //////////////////////////////////////////////////////////////////////////////// | |
| 141 // Constructors/Destructors | |
| 142 | |
| 143 GpuMemoryManager::GpuMemoryManager(GpuChannelManager* channel_manager) | |
| 144 : channel_manager_(channel_manager) { | |
| 145 | |
| 146 } | |
| 147 | |
| 148 GpuMemoryManager::~GpuMemoryManager() { | |
| 149 } | |
| 150 | |
| 151 //////////////////////////////////////////////////////////////////////////////// | |
| 152 | |
| 153 void GpuMemoryManager::Manage() const { | |
| 154 // Compute RenderWidgetDescriptors from GpuCommandBufferStubs | |
| 155 std::vector<GpuCommandBufferStub*> stubs = GetGpuCommandBufferStubs( | |
| 156 channel_manager_); | |
| 157 std::vector<RenderWidgetDescriptor*> render_widget_descriptors = | |
| 158 ComputeRenderWidgetDescriptorsFromStubs(stubs); | |
| 159 | |
| 160 // Sort them in {visibility,last_used_time} order using custom sorter | |
| 161 std::sort(render_widget_descriptors.begin(), render_widget_descriptors.end(), | |
| 162 RenderWidgetDescriptorSorter()); | |
| 163 | |
| 164 // TODO(mmocny): What follows is vastly simplified logic based on counts, | |
| 165 // should consider actual memory usage and availability. | |
| 166 | |
| 167 // Separate into three sets, identified by render_widget_id | |
| 168 // 1. all_buffers: Every visible RenderWidget must have all buffers. | |
| 169 // 2. front_buffers: Invisible RenderWidgets can have a frontbuffer if the | |
| 170 // the total count is under some soft limit. | |
| 171 // 3. no_buffers: The rest should drop all buffers. | |
| 172 // TODO(mmocny): all_buffers takes up ~3 times more memory than front_buffers. | |
| 173 // Couldn't we have 3 front_buffer per each all_buffer? | |
| 174 std::set<int> all_buffers, front_buffers, no_buffers; | |
| 175 static const size_t kMaxFrontBufferSoftLimit = 8; | |
| 176 | |
| 177 for (std::vector<RenderWidgetDescriptor*>::iterator rwds_it = | |
| 178 render_widget_descriptors.begin(); | |
| 179 rwds_it != render_widget_descriptors.end(); ++rwds_it) { | |
| 180 RenderWidgetDescriptor* rwd = *rwds_it; | |
| 181 if (rwd->visible()) | |
| 182 all_buffers.insert(rwd->render_widget_id()); | |
| 183 else if ((all_buffers.size() + front_buffers.size()) < | |
| 184 kMaxFrontBufferSoftLimit) | |
| 185 front_buffers.insert(rwd->render_widget_id()); | |
| 186 else | |
| 187 no_buffers.insert(rwd->render_widget_id()); | |
| 188 } | |
| 189 | |
| 190 // Now, go through the command buffer stubs, and match their render widgets | |
| 191 // up to the buckets we divided. Since they may be associated with | |
| 192 // RenderWidgets in various buckets, the most visible one takes priority | |
| 193 for (std::vector<GpuCommandBufferStub*>::const_iterator it = stubs.begin(); | |
| 194 it != stubs.end(); ++it) { | |
| 195 GpuCommandBufferStub* stub = *it; | |
| 196 GpuMemoryAllocation allocation; | |
| 197 std::vector<int> render_widget_ids = stub->render_widget_ids(); | |
| 198 if (std::find_first_of(all_buffers.begin(), all_buffers.end(), | |
| 199 render_widget_ids.begin(), render_widget_ids.end()) != | |
| 200 all_buffers.end()) { | |
| 201 allocation.gpuResourceSizeInBytes = | |
| 202 GpuMemoryAllocation::kResourceSizeForegroundTab; | |
| 203 allocation.hasFrontbuffer = true; | |
| 204 allocation.hasBackbuffer = true; | |
| 205 } else if (std::find_first_of(front_buffers.begin(), front_buffers.end(), | |
| 206 render_widget_ids.begin(), render_widget_ids.end()) != | |
| 207 front_buffers.end()) { | |
| 208 allocation.gpuResourceSizeInBytes = | |
| 209 GpuMemoryAllocation::kResourceSizeBackgroundTab; | |
| 210 allocation.hasFrontbuffer = true; | |
| 211 allocation.hasBackbuffer = false; | |
| 212 } else { | |
| 213 allocation.gpuResourceSizeInBytes = | |
| 214 GpuMemoryAllocation::kResourceSizeHibernatedTab; | |
| 215 allocation.hasFrontbuffer = false; | |
| 216 allocation.hasBackbuffer = false; | |
| 217 } | |
| 218 stub->SetMemoryAllocation(allocation); | |
| 219 } | |
| 220 } | |
| 221 | |
|
nduca
2012/01/27 10:10:13
No tests? That is scary.
It loosk like we dont ha
Ken Russell (switch to Gerrit)
2012/01/27 19:21:24
+1 to testing this from the start.
I haven't been
mmocny
2012/01/27 19:51:33
ok.
On 2012/01/27 10:10:13, nduca wrote:
| |
| 222 //////////////////////////////////////////////////////////////////////////////// | |
| 223 | |
| 224 #endif | |
| OLD | NEW |