blob: fa7c83c759cc416356cb7639b769e9d4e72055fa [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/command_buffer/service/transfer_buffer_manager.h"
#include <limits>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/process/process_handle.h"
#include "base/strings/stringprintf.h"
#include "base/thread_task_runner_handle.h"
#include "base/trace_event/memory_allocator_dump.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/trace_event.h"
#include "gpu/command_buffer/common/cmd_buffer_common.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "gpu/command_buffer/service/memory_tracking.h"
using ::base::SharedMemory;
namespace gpu {
TransferBufferManagerInterface::~TransferBufferManagerInterface() {
}
TransferBufferManager::TransferBufferManager(
gles2::MemoryTracker* memory_tracker)
: shared_memory_bytes_allocated_(0), memory_tracker_(memory_tracker) {}
TransferBufferManager::~TransferBufferManager() {
while (!registered_buffers_.empty()) {
BufferMap::iterator it = registered_buffers_.begin();
DCHECK(shared_memory_bytes_allocated_ >= it->second->size());
shared_memory_bytes_allocated_ -= it->second->size();
registered_buffers_.erase(it);
}
DCHECK(!shared_memory_bytes_allocated_);
base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
this);
}
bool TransferBufferManager::Initialize() {
// When created from InProcessCommandBuffer, we won't have a |memory_tracker_|
// so don't register a dump provider.
if (memory_tracker_) {
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
this, base::ThreadTaskRunnerHandle::Get());
}
return true;
}
bool TransferBufferManager::RegisterTransferBuffer(
int32 id,
scoped_ptr<BufferBacking> buffer_backing) {
if (id <= 0) {
DVLOG(0) << "Cannot register transfer buffer with non-positive ID.";
return false;
}
// Fail if the ID is in use.
if (registered_buffers_.find(id) != registered_buffers_.end()) {
DVLOG(0) << "Buffer ID already in use.";
return false;
}
// Register the shared memory with the ID.
scoped_refptr<Buffer> buffer(new gpu::Buffer(buffer_backing.Pass()));
// Check buffer alignment is sane.
DCHECK(!(reinterpret_cast<uintptr_t>(buffer->memory()) &
(kCommandBufferEntrySize - 1)));
shared_memory_bytes_allocated_ += buffer->size();
registered_buffers_[id] = buffer;
return true;
}
void TransferBufferManager::DestroyTransferBuffer(int32 id) {
BufferMap::iterator it = registered_buffers_.find(id);
if (it == registered_buffers_.end()) {
DVLOG(0) << "Transfer buffer ID was not registered.";
return;
}
DCHECK(shared_memory_bytes_allocated_ >= it->second->size());
shared_memory_bytes_allocated_ -= it->second->size();
registered_buffers_.erase(it);
}
scoped_refptr<Buffer> TransferBufferManager::GetTransferBuffer(int32 id) {
if (id == 0)
return NULL;
BufferMap::iterator it = registered_buffers_.find(id);
if (it == registered_buffers_.end())
return NULL;
return it->second;
}
bool TransferBufferManager::OnMemoryDump(
const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) {
for (const auto& buffer_entry : registered_buffers_) {
int32 buffer_id = buffer_entry.first;
const Buffer* buffer = buffer_entry.second.get();
std::string dump_name =
base::StringPrintf("gpu/transfer_memory/client_%d/buffer_%d",
memory_tracker_->ClientId(), buffer_id);
base::trace_event::MemoryAllocatorDump* dump =
pmd->CreateAllocatorDump(dump_name);
dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
buffer->size());
auto guid =
GetBufferGUIDForTracing(memory_tracker_->ClientTracingId(), buffer_id);
pmd->CreateSharedGlobalAllocatorDump(guid);
pmd->AddOwnershipEdge(dump->guid(), guid);
}
return true;
}
} // namespace gpu