mapped_memory.cc revision f2477e01787aa58f445919b809d89e252beef54f
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
14namespace gpu {
15
16MemoryChunk::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
23MappedMemoryManager::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
31MappedMemoryManager::~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
40void* 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
98void 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
109void 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
120void 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