15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "gpu/command_buffer/client/mapped_memory.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <functional>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/debug/trace_event.h"
11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/logging.h"
1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "gpu/command_buffer/client/cmd_buffer_helper.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace gpu {
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochMemoryChunk::MemoryChunk(int32 shm_id,
17effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                         scoped_refptr<gpu::Buffer> shm,
184ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch                         CommandBufferHelper* helper,
194ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch                         const base::Closure& poll_callback)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : shm_id_(shm_id),
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shm_(shm),
224ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch      allocator_(shm->size(), helper, poll_callback, shm->memory()) {}
23effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
24effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochMemoryChunk::~MemoryChunk() {}
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)MappedMemoryManager::MappedMemoryManager(CommandBufferHelper* helper,
274ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch                                         const base::Closure& poll_callback,
283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                         size_t unused_memory_reclaim_limit)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : chunk_size_multiple_(1),
303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      helper_(helper),
314ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch      poll_callback_(poll_callback),
323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      allocated_memory_(0),
333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      max_free_bytes_(unused_memory_reclaim_limit) {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MappedMemoryManager::~MappedMemoryManager() {
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CommandBuffer* cmd_buf = helper_->command_buffer();
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (MemoryChunkVector::iterator iter = chunks_.begin();
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       iter != chunks_.end(); ++iter) {
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    MemoryChunk* chunk = *iter;
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    cmd_buf->DestroyTransferBuffer(chunk->shm_id());
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* MappedMemoryManager::Alloc(
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int size, int32* shm_id, unsigned int* shm_offset) {
47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(shm_id);
48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(shm_offset);
493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (size <= allocated_memory_) {
503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    size_t total_bytes_in_use = 0;
513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // See if any of the chunks can satisfy this request.
523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    for (size_t ii = 0; ii < chunks_.size(); ++ii) {
533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      MemoryChunk* chunk = chunks_[ii];
543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      chunk->FreeUnused();
553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      total_bytes_in_use += chunk->bytes_in_use();
563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (chunk->GetLargestFreeSizeWithoutWaiting() >= size) {
573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        void* mem = chunk->Alloc(size);
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        DCHECK(mem);
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        *shm_id = chunk->shm_id();
603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        *shm_offset = chunk->GetOffset(mem);
613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return mem;
623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // If there is a memory limit being enforced and total free
663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // memory (allocated_memory_ - total_bytes_in_use) is larger than
673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // the limit try waiting.
683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (max_free_bytes_ != kNoLimit &&
693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        (allocated_memory_ - total_bytes_in_use) >= max_free_bytes_) {
703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      TRACE_EVENT0("gpu", "MappedMemoryManager::Alloc::wait");
713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      for (size_t ii = 0; ii < chunks_.size(); ++ii) {
723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        MemoryChunk* chunk = chunks_[ii];
733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (chunk->GetLargestFreeSizeWithWaiting() >= size) {
743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          void* mem = chunk->Alloc(size);
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          DCHECK(mem);
763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          *shm_id = chunk->shm_id();
773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          *shm_offset = chunk->GetOffset(mem);
783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          return mem;
793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make a new chunk to satisfy the request.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandBuffer* cmd_buf = helper_->command_buffer();
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int chunk_size =
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ((size + chunk_size_multiple_ - 1) / chunk_size_multiple_) *
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chunk_size_multiple_;
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int32 id = -1;
90effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_refptr<gpu::Buffer> shm =
91effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      cmd_buf->CreateTransferBuffer(chunk_size, &id);
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (id  < 0)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
94e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK(shm);
954ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch  MemoryChunk* mc = new MemoryChunk(id, shm, helper_, poll_callback_);
963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  allocated_memory_ += mc->GetSize();
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chunks_.push_back(mc);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* mem = mc->Alloc(size);
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(mem);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *shm_id = mc->shm_id();
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *shm_offset = mc->GetOffset(mem);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mem;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MappedMemoryManager::Free(void* pointer) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t ii = 0; ii < chunks_.size(); ++ii) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MemoryChunk* chunk = chunks_[ii];
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (chunk->IsInChunk(pointer)) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chunk->Free(pointer);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  NOTREACHED();
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MappedMemoryManager::FreePendingToken(void* pointer, int32 token) {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t ii = 0; ii < chunks_.size(); ++ii) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MemoryChunk* chunk = chunks_[ii];
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (chunk->IsInChunk(pointer)) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chunk->FreePendingToken(pointer, token);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  NOTREACHED();
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MappedMemoryManager::FreeUnused() {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandBuffer* cmd_buf = helper_->command_buffer();
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MemoryChunkVector::iterator iter = chunks_.begin();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (iter != chunks_.end()) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MemoryChunk* chunk = *iter;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chunk->FreeUnused();
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!chunk->InUse()) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd_buf->DestroyTransferBuffer(chunk->shm_id());
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      allocated_memory_ -= chunk->GetSize();
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iter = chunks_.erase(iter);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++iter;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace gpu
144