1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
// 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
|