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