1 // Copyright (c) 2011 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 "gpu/command_buffer/client/mapped_memory.h"
6
7 #include <algorithm>
8 #include <functional>
9
10 #include "base/debug/trace_event.h"
11 #include "base/logging.h"
12 #include "gpu/command_buffer/client/cmd_buffer_helper.h"
13
14 namespace gpu {
15
MemoryChunk(int32 shm_id,gpu::Buffer shm,CommandBufferHelper * helper)16 MemoryChunk::MemoryChunk(
17 int32 shm_id, gpu::Buffer shm, CommandBufferHelper* helper)
18 : shm_id_(shm_id),
19 shm_(shm),
20 allocator_(shm.size, helper, shm.ptr) {
21 }
22
MappedMemoryManager(CommandBufferHelper * helper,size_t unused_memory_reclaim_limit)23 MappedMemoryManager::MappedMemoryManager(CommandBufferHelper* helper,
24 size_t unused_memory_reclaim_limit)
25 : chunk_size_multiple_(1),
26 helper_(helper),
27 allocated_memory_(0),
28 max_free_bytes_(unused_memory_reclaim_limit) {
29 }
30
~MappedMemoryManager()31 MappedMemoryManager::~MappedMemoryManager() {
32 CommandBuffer* cmd_buf = helper_->command_buffer();
33 for (MemoryChunkVector::iterator iter = chunks_.begin();
34 iter != chunks_.end(); ++iter) {
35 MemoryChunk* chunk = *iter;
36 cmd_buf->DestroyTransferBuffer(chunk->shm_id());
37 }
38 }
39
Alloc(unsigned int size,int32 * shm_id,unsigned int * shm_offset)40 void* MappedMemoryManager::Alloc(
41 unsigned int size, int32* shm_id, unsigned int* shm_offset) {
42 DCHECK(shm_id);
43 DCHECK(shm_offset);
44 if (size <= allocated_memory_) {
45 size_t total_bytes_in_use = 0;
46 // See if any of the chunks can satisfy this request.
47 for (size_t ii = 0; ii < chunks_.size(); ++ii) {
48 MemoryChunk* chunk = chunks_[ii];
49 chunk->FreeUnused();
50 total_bytes_in_use += chunk->bytes_in_use();
51 if (chunk->GetLargestFreeSizeWithoutWaiting() >= size) {
52 void* mem = chunk->Alloc(size);
53 DCHECK(mem);
54 *shm_id = chunk->shm_id();
55 *shm_offset = chunk->GetOffset(mem);
56 return mem;
57 }
58 }
59
60 // If there is a memory limit being enforced and total free
61 // memory (allocated_memory_ - total_bytes_in_use) is larger than
62 // the limit try waiting.
63 if (max_free_bytes_ != kNoLimit &&
64 (allocated_memory_ - total_bytes_in_use) >= max_free_bytes_) {
65 TRACE_EVENT0("gpu", "MappedMemoryManager::Alloc::wait");
66 for (size_t ii = 0; ii < chunks_.size(); ++ii) {
67 MemoryChunk* chunk = chunks_[ii];
68 if (chunk->GetLargestFreeSizeWithWaiting() >= size) {
69 void* mem = chunk->Alloc(size);
70 DCHECK(mem);
71 *shm_id = chunk->shm_id();
72 *shm_offset = chunk->GetOffset(mem);
73 return mem;
74 }
75 }
76 }
77 }
78
79 // Make a new chunk to satisfy the request.
80 CommandBuffer* cmd_buf = helper_->command_buffer();
81 unsigned int chunk_size =
82 ((size + chunk_size_multiple_ - 1) / chunk_size_multiple_) *
83 chunk_size_multiple_;
84 int32 id = -1;
85 gpu::Buffer shm = cmd_buf->CreateTransferBuffer(chunk_size, &id);
86 if (id < 0)
87 return NULL;
88 MemoryChunk* mc = new MemoryChunk(id, shm, helper_);
89 allocated_memory_ += mc->GetSize();
90 chunks_.push_back(mc);
91 void* mem = mc->Alloc(size);
92 DCHECK(mem);
93 *shm_id = mc->shm_id();
94 *shm_offset = mc->GetOffset(mem);
95 return mem;
96 }
97
Free(void * pointer)98 void MappedMemoryManager::Free(void* pointer) {
99 for (size_t ii = 0; ii < chunks_.size(); ++ii) {
100 MemoryChunk* chunk = chunks_[ii];
101 if (chunk->IsInChunk(pointer)) {
102 chunk->Free(pointer);
103 return;
104 }
105 }
106 NOTREACHED();
107 }
108
FreePendingToken(void * pointer,int32 token)109 void MappedMemoryManager::FreePendingToken(void* pointer, int32 token) {
110 for (size_t ii = 0; ii < chunks_.size(); ++ii) {
111 MemoryChunk* chunk = chunks_[ii];
112 if (chunk->IsInChunk(pointer)) {
113 chunk->FreePendingToken(pointer, token);
114 return;
115 }
116 }
117 NOTREACHED();
118 }
119
FreeUnused()120 void MappedMemoryManager::FreeUnused() {
121 CommandBuffer* cmd_buf = helper_->command_buffer();
122 MemoryChunkVector::iterator iter = chunks_.begin();
123 while (iter != chunks_.end()) {
124 MemoryChunk* chunk = *iter;
125 chunk->FreeUnused();
126 if (!chunk->InUse()) {
127 cmd_buf->DestroyTransferBuffer(chunk->shm_id());
128 allocated_memory_ -= chunk->GetSize();
129 iter = chunks_.erase(iter);
130 } else {
131 ++iter;
132 }
133 }
134 }
135
136 } // namespace gpu
137