blob: 7bde12ab33d19a248e6f6645e5018b3d3c18e1f7 [file] [log] [blame] [edit]
// 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/process_util.h"
#include "base/debug/trace_event.h"
using ::base::SharedMemory;
namespace gpu {
TransferBufferManagerInterface::~TransferBufferManagerInterface() {
}
TransferBufferManager::TransferBufferManager()
: shared_memory_bytes_allocated_(0) {
// Element zero is always NULL.
registered_objects_.push_back(Buffer());
}
TransferBufferManager::~TransferBufferManager() {
for (size_t i = 0; i < registered_objects_.size(); ++i) {
if (registered_objects_[i].shared_memory) {
DCHECK(shared_memory_bytes_allocated_ >= registered_objects_[i].size);
shared_memory_bytes_allocated_ -= registered_objects_[i].size;
delete registered_objects_[i].shared_memory;
}
}
DCHECK(!shared_memory_bytes_allocated_);
}
bool TransferBufferManager::Initialize() {
return true;
}
int32 TransferBufferManager::CreateTransferBuffer(
size_t size, int32 id_request) {
SharedMemory buffer;
if (!buffer.CreateAnonymous(size))
return -1;
return RegisterTransferBuffer(&buffer, size, id_request);
}
int32 TransferBufferManager::RegisterTransferBuffer(
base::SharedMemory* shared_memory, size_t size, int32 id_request) {
// Check we haven't exceeded the range that fits in a 32-bit integer.
if (unused_registered_object_elements_.empty()) {
if (registered_objects_.size() > std::numeric_limits<uint32>::max())
return -1;
}
// Check that the requested ID is sane (not too large, or less than -1)
if (id_request != -1 && (id_request > 100 || id_request < -1))
return -1;
// Duplicate the handle.
base::SharedMemoryHandle duped_shared_memory_handle;
if (!shared_memory->ShareToProcess(base::GetCurrentProcessHandle(),
&duped_shared_memory_handle)) {
return -1;
}
scoped_ptr<SharedMemory> duped_shared_memory(
new SharedMemory(duped_shared_memory_handle, false));
// Map the shared memory into this process. This validates the size.
if (!duped_shared_memory->Map(size))
return -1;
// If it could be mapped, allocate an ID and register the shared memory with
// that ID.
Buffer buffer;
buffer.ptr = duped_shared_memory->memory();
buffer.size = size;
buffer.shared_memory = duped_shared_memory.release();
shared_memory_bytes_allocated_ += size;
TRACE_COUNTER_ID1(
"gpu", "GpuTransferBufferMemory", this, shared_memory_bytes_allocated_);
// If caller requested specific id, first try to use id_request.
if (id_request != -1) {
int32 cur_size = static_cast<int32>(registered_objects_.size());
if (cur_size <= id_request) {
// Pad registered_objects_ to reach id_request.
registered_objects_.resize(static_cast<size_t>(id_request + 1));
for (int32 id = cur_size; id < id_request; ++id)
unused_registered_object_elements_.insert(id);
registered_objects_[id_request] = buffer;
return id_request;
} else if (!registered_objects_[id_request].shared_memory) {
// id_request is already in free list.
registered_objects_[id_request] = buffer;
unused_registered_object_elements_.erase(id_request);
return id_request;
}
}
if (unused_registered_object_elements_.empty()) {
int32 handle = static_cast<int32>(registered_objects_.size());
registered_objects_.push_back(buffer);
return handle;
} else {
int32 handle = *unused_registered_object_elements_.begin();
unused_registered_object_elements_.erase(
unused_registered_object_elements_.begin());
DCHECK(!registered_objects_[handle].shared_memory);
registered_objects_[handle] = buffer;
return handle;
}
}
void TransferBufferManager::DestroyTransferBuffer(int32 handle) {
if (handle <= 0)
return;
if (static_cast<size_t>(handle) >= registered_objects_.size())
return;
DCHECK(shared_memory_bytes_allocated_ >= registered_objects_[handle].size);
shared_memory_bytes_allocated_ -= registered_objects_[handle].size;
TRACE_COUNTER_ID1(
"CommandBuffer", "SharedMemory", this, shared_memory_bytes_allocated_);
delete registered_objects_[handle].shared_memory;
registered_objects_[handle] = Buffer();
unused_registered_object_elements_.insert(handle);
// Remove all null objects from the end of the vector. This allows the vector
// to shrink when, for example, all objects are unregistered. Note that this
// loop never removes element zero, which is always NULL.
while (registered_objects_.size() > 1 &&
!registered_objects_.back().shared_memory) {
registered_objects_.pop_back();
unused_registered_object_elements_.erase(
static_cast<int32>(registered_objects_.size()));
}
}
Buffer TransferBufferManager::GetTransferBuffer(int32 handle) {
if (handle < 0)
return Buffer();
if (static_cast<size_t>(handle) >= registered_objects_.size())
return Buffer();
return registered_objects_[handle];
}
} // namespace gpu