OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/viz/host/server_gpu_memory_buffer_manager.h" | 5 #include "components/viz/host/server_gpu_memory_buffer_manager.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/strings/stringprintf.h" |
8 #include "base/threading/sequenced_task_runner_handle.h" | 9 #include "base/threading/sequenced_task_runner_handle.h" |
| 10 #include "base/trace_event/memory_dump_manager.h" |
| 11 #include "base/trace_event/process_memory_dump.h" |
9 #include "gpu/ipc/client/gpu_memory_buffer_impl.h" | 12 #include "gpu/ipc/client/gpu_memory_buffer_impl.h" |
10 #include "gpu/ipc/client/gpu_memory_buffer_impl_shared_memory.h" | 13 #include "gpu/ipc/client/gpu_memory_buffer_impl_shared_memory.h" |
11 #include "gpu/ipc/common/gpu_memory_buffer_support.h" | 14 #include "gpu/ipc/common/gpu_memory_buffer_support.h" |
12 #include "services/ui/gpu/interfaces/gpu_service.mojom.h" | 15 #include "services/ui/gpu/interfaces/gpu_service.mojom.h" |
| 16 #include "ui/gfx/buffer_format_util.h" |
| 17 #include "ui/gfx/gpu_memory_buffer_tracing.h" |
13 | 18 |
14 namespace viz { | 19 namespace viz { |
15 | 20 |
| 21 ServerGpuMemoryBufferManager::BufferInfo::BufferInfo() = default; |
| 22 ServerGpuMemoryBufferManager::BufferInfo::~BufferInfo() = default; |
| 23 |
16 ServerGpuMemoryBufferManager::ServerGpuMemoryBufferManager( | 24 ServerGpuMemoryBufferManager::ServerGpuMemoryBufferManager( |
17 ui::mojom::GpuService* gpu_service, | 25 ui::mojom::GpuService* gpu_service, |
18 int client_id) | 26 int client_id) |
19 : gpu_service_(gpu_service), | 27 : gpu_service_(gpu_service), |
20 client_id_(client_id), | 28 client_id_(client_id), |
21 native_configurations_(gpu::GetNativeGpuMemoryBufferConfigurations()), | 29 native_configurations_(gpu::GetNativeGpuMemoryBufferConfigurations()), |
22 task_runner_(base::SequencedTaskRunnerHandle::Get()), | 30 task_runner_(base::SequencedTaskRunnerHandle::Get()), |
23 weak_factory_(this) {} | 31 weak_factory_(this) {} |
24 | 32 |
25 ServerGpuMemoryBufferManager::~ServerGpuMemoryBufferManager() {} | 33 ServerGpuMemoryBufferManager::~ServerGpuMemoryBufferManager() {} |
26 | 34 |
27 void ServerGpuMemoryBufferManager::AllocateGpuMemoryBuffer( | 35 void ServerGpuMemoryBufferManager::AllocateGpuMemoryBuffer( |
28 gfx::GpuMemoryBufferId id, | 36 gfx::GpuMemoryBufferId id, |
29 int client_id, | 37 int client_id, |
30 const gfx::Size& size, | 38 const gfx::Size& size, |
31 gfx::BufferFormat format, | 39 gfx::BufferFormat format, |
32 gfx::BufferUsage usage, | 40 gfx::BufferUsage usage, |
33 gpu::SurfaceHandle surface_handle, | 41 gpu::SurfaceHandle surface_handle, |
34 base::OnceCallback<void(const gfx::GpuMemoryBufferHandle&)> callback) { | 42 base::OnceCallback<void(const gfx::GpuMemoryBufferHandle&)> callback) { |
35 DCHECK(task_runner_->RunsTasksInCurrentSequence()); | 43 DCHECK(task_runner_->RunsTasksInCurrentSequence()); |
36 if (gpu::GetNativeGpuMemoryBufferType() != gfx::EMPTY_BUFFER) { | 44 if (gpu::GetNativeGpuMemoryBufferType() != gfx::EMPTY_BUFFER) { |
37 const bool is_native = native_configurations_.find(std::make_pair( | 45 const bool is_native = native_configurations_.find(std::make_pair( |
38 format, usage)) != native_configurations_.end(); | 46 format, usage)) != native_configurations_.end(); |
39 if (is_native) { | 47 if (is_native) { |
40 pending_buffers_.insert(client_id); | 48 pending_buffers_.insert(client_id); |
41 gpu_service_->CreateGpuMemoryBuffer( | 49 gpu_service_->CreateGpuMemoryBuffer( |
42 id, size, format, usage, client_id, surface_handle, | 50 id, size, format, usage, client_id, surface_handle, |
43 base::Bind(&ServerGpuMemoryBufferManager::OnGpuMemoryBufferAllocated, | 51 base::Bind(&ServerGpuMemoryBufferManager::OnGpuMemoryBufferAllocated, |
44 weak_factory_.GetWeakPtr(), client_id, | 52 weak_factory_.GetWeakPtr(), client_id, |
| 53 gfx::BufferSizeForBufferFormat(size, format), |
45 base::Passed(std::move(callback)))); | 54 base::Passed(std::move(callback)))); |
46 return; | 55 return; |
47 } | 56 } |
48 } | 57 } |
49 | 58 |
50 gfx::GpuMemoryBufferHandle buffer_handle; | 59 gfx::GpuMemoryBufferHandle buffer_handle; |
51 // The requests are coming in from untrusted clients. So verify that it is | 60 // The requests are coming in from untrusted clients. So verify that it is |
52 // possible to allocate shared memory buffer first. | 61 // possible to allocate shared memory buffer first. |
53 if (gpu::GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage) && | 62 if (gpu::GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage) && |
54 gpu::GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size, | 63 gpu::GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size, |
55 format)) { | 64 format)) { |
56 buffer_handle = gpu::GpuMemoryBufferImplSharedMemory::CreateGpuMemoryBuffer( | 65 buffer_handle = gpu::GpuMemoryBufferImplSharedMemory::CreateGpuMemoryBuffer( |
57 id, size, format); | 66 id, size, format); |
| 67 BufferInfo buffer_info; |
| 68 DCHECK_EQ(gfx::SHARED_MEMORY_BUFFER, buffer_handle.type); |
| 69 buffer_info.type = gfx::SHARED_MEMORY_BUFFER; |
| 70 buffer_info.buffer_size_in_bytes = |
| 71 gfx::BufferSizeForBufferFormat(size, format); |
| 72 buffer_info.shared_memory_guid = buffer_handle.handle.GetGUID(); |
| 73 allocated_buffers_[client_id].insert( |
| 74 std::make_pair(buffer_handle.id, buffer_info)); |
58 } | 75 } |
59 | 76 |
60 task_runner_->PostTask(FROM_HERE, | 77 task_runner_->PostTask(FROM_HERE, |
61 base::BindOnce(std::move(callback), buffer_handle)); | 78 base::BindOnce(std::move(callback), buffer_handle)); |
62 } | 79 } |
63 | 80 |
64 std::unique_ptr<gfx::GpuMemoryBuffer> | 81 std::unique_ptr<gfx::GpuMemoryBuffer> |
65 ServerGpuMemoryBufferManager::CreateGpuMemoryBuffer( | 82 ServerGpuMemoryBufferManager::CreateGpuMemoryBuffer( |
66 const gfx::Size& size, | 83 const gfx::Size& size, |
67 gfx::BufferFormat format, | 84 gfx::BufferFormat format, |
(...skipping 29 matching lines...) Expand all Loading... |
97 weak_factory_.GetWeakPtr(), id, client_id_)); | 114 weak_factory_.GetWeakPtr(), id, client_id_)); |
98 } | 115 } |
99 | 116 |
100 void ServerGpuMemoryBufferManager::SetDestructionSyncToken( | 117 void ServerGpuMemoryBufferManager::SetDestructionSyncToken( |
101 gfx::GpuMemoryBuffer* buffer, | 118 gfx::GpuMemoryBuffer* buffer, |
102 const gpu::SyncToken& sync_token) { | 119 const gpu::SyncToken& sync_token) { |
103 static_cast<gpu::GpuMemoryBufferImpl*>(buffer)->set_destruction_sync_token( | 120 static_cast<gpu::GpuMemoryBufferImpl*>(buffer)->set_destruction_sync_token( |
104 sync_token); | 121 sync_token); |
105 } | 122 } |
106 | 123 |
| 124 bool ServerGpuMemoryBufferManager::OnMemoryDump( |
| 125 const base::trace_event::MemoryDumpArgs& args, |
| 126 base::trace_event::ProcessMemoryDump* pmd) { |
| 127 DCHECK(task_runner_->RunsTasksInCurrentSequence()); |
| 128 for (const auto& pair : allocated_buffers_) { |
| 129 int client_id = pair.first; |
| 130 for (const auto& buffer_pair : pair.second) { |
| 131 gfx::GpuMemoryBufferId buffer_id = buffer_pair.first; |
| 132 const BufferInfo& buffer_info = buffer_pair.second; |
| 133 base::trace_event::MemoryAllocatorDump* dump = |
| 134 pmd->CreateAllocatorDump(base::StringPrintf( |
| 135 "gpumemorybuffer/client_%d/buffer_%d", client_id, buffer_id.id)); |
| 136 if (!dump) |
| 137 return false; |
| 138 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, |
| 139 base::trace_event::MemoryAllocatorDump::kUnitsBytes, |
| 140 buffer_info.buffer_size_in_bytes); |
| 141 |
| 142 // Create the cross-process ownership edge. If the client creates a |
| 143 // corresponding dump for the same buffer, this will avoid to |
| 144 // double-count them in tracing. If, instead, no other process will emit a |
| 145 // dump with the same guid, the segment will be accounted to the browser. |
| 146 uint64_t client_tracing_process_id = ClientIdToTracingId(client_id); |
| 147 |
| 148 if (buffer_info.type == gfx::SHARED_MEMORY_BUFFER) { |
| 149 auto shared_buffer_guid = gfx::GetSharedMemoryGUIDForTracing( |
| 150 client_tracing_process_id, buffer_id); |
| 151 pmd->CreateSharedMemoryOwnershipEdge(dump->guid(), shared_buffer_guid, |
| 152 buffer_info.shared_memory_guid, |
| 153 0 /* importance */); |
| 154 } else { |
| 155 auto shared_buffer_guid = gfx::GetGenericSharedGpuMemoryGUIDForTracing( |
| 156 client_tracing_process_id, buffer_id); |
| 157 pmd->CreateSharedGlobalAllocatorDump(shared_buffer_guid); |
| 158 pmd->AddOwnershipEdge(dump->guid(), shared_buffer_guid); |
| 159 } |
| 160 } |
| 161 } |
| 162 return true; |
| 163 } |
| 164 |
107 void ServerGpuMemoryBufferManager::DestroyGpuMemoryBuffer( | 165 void ServerGpuMemoryBufferManager::DestroyGpuMemoryBuffer( |
108 gfx::GpuMemoryBufferId id, | 166 gfx::GpuMemoryBufferId id, |
109 int client_id, | 167 int client_id, |
110 const gpu::SyncToken& sync_token) { | 168 const gpu::SyncToken& sync_token) { |
111 DCHECK(task_runner_->RunsTasksInCurrentSequence()); | 169 DCHECK(task_runner_->RunsTasksInCurrentSequence()); |
112 if (native_buffers_[client_id].erase(id)) | 170 auto iter = allocated_buffers_[client_id].find(id); |
| 171 if (iter == allocated_buffers_[client_id].end()) |
| 172 return; |
| 173 DCHECK_NE(gfx::EMPTY_BUFFER, iter->second.type); |
| 174 allocated_buffers_[client_id].erase(id); |
| 175 if (iter->second.type != gfx::SHARED_MEMORY_BUFFER) |
113 gpu_service_->DestroyGpuMemoryBuffer(id, client_id, sync_token); | 176 gpu_service_->DestroyGpuMemoryBuffer(id, client_id, sync_token); |
114 } | 177 } |
115 | 178 |
116 void ServerGpuMemoryBufferManager::DestroyAllGpuMemoryBufferForClient( | 179 void ServerGpuMemoryBufferManager::DestroyAllGpuMemoryBufferForClient( |
117 int client_id) { | 180 int client_id) { |
118 DCHECK(task_runner_->RunsTasksInCurrentSequence()); | 181 DCHECK(task_runner_->RunsTasksInCurrentSequence()); |
119 for (gfx::GpuMemoryBufferId id : native_buffers_[client_id]) | 182 for (auto pair : allocated_buffers_[client_id]) { |
120 gpu_service_->DestroyGpuMemoryBuffer(id, client_id, gpu::SyncToken()); | 183 DCHECK_NE(gfx::EMPTY_BUFFER, pair.second.type); |
121 native_buffers_.erase(client_id); | 184 if (pair.second.type != gfx::SHARED_MEMORY_BUFFER) { |
| 185 gpu_service_->DestroyGpuMemoryBuffer(pair.first, client_id, |
| 186 gpu::SyncToken()); |
| 187 } |
| 188 } |
| 189 allocated_buffers_.erase(client_id); |
122 pending_buffers_.erase(client_id); | 190 pending_buffers_.erase(client_id); |
123 } | 191 } |
124 | 192 |
| 193 uint64_t ServerGpuMemoryBufferManager::ClientIdToTracingId( |
| 194 int client_id) const { |
| 195 if (client_id == client_id_) { |
| 196 return base::trace_event::MemoryDumpManager::GetInstance() |
| 197 ->GetTracingProcessId(); |
| 198 } |
| 199 // TODO(sad|ssid): Find a better way once crbug.com/661257 is resolved. |
| 200 // The hash value is incremented so that the tracing id is never equal to |
| 201 // MemoryDumpManager::kInvalidTracingProcessId. |
| 202 return static_cast<uint64_t>(base::Hash( |
| 203 reinterpret_cast<const char*>(&client_id), sizeof(client_id))) + |
| 204 1; |
| 205 } |
| 206 |
125 void ServerGpuMemoryBufferManager::OnGpuMemoryBufferAllocated( | 207 void ServerGpuMemoryBufferManager::OnGpuMemoryBufferAllocated( |
126 int client_id, | 208 int client_id, |
| 209 size_t buffer_size_in_bytes, |
127 base::OnceCallback<void(const gfx::GpuMemoryBufferHandle&)> callback, | 210 base::OnceCallback<void(const gfx::GpuMemoryBufferHandle&)> callback, |
128 const gfx::GpuMemoryBufferHandle& handle) { | 211 const gfx::GpuMemoryBufferHandle& handle) { |
129 DCHECK(task_runner_->RunsTasksInCurrentSequence()); | 212 DCHECK(task_runner_->RunsTasksInCurrentSequence()); |
130 if (pending_buffers_.find(client_id) == pending_buffers_.end()) { | 213 if (pending_buffers_.find(client_id) == pending_buffers_.end()) { |
131 // The client has been destroyed since the allocation request was made. | 214 // The client has been destroyed since the allocation request was made. |
132 if (!handle.is_null()) { | 215 if (!handle.is_null()) { |
133 gpu_service_->DestroyGpuMemoryBuffer(handle.id, client_id, | 216 gpu_service_->DestroyGpuMemoryBuffer(handle.id, client_id, |
134 gpu::SyncToken()); | 217 gpu::SyncToken()); |
135 } | 218 } |
136 std::move(callback).Run(gfx::GpuMemoryBufferHandle()); | 219 std::move(callback).Run(gfx::GpuMemoryBufferHandle()); |
137 return; | 220 return; |
138 } | 221 } |
139 if (!handle.is_null()) | 222 if (!handle.is_null()) { |
140 native_buffers_[client_id].insert(handle.id); | 223 BufferInfo buffer_info; |
| 224 buffer_info.type = handle.type; |
| 225 buffer_info.buffer_size_in_bytes = buffer_size_in_bytes; |
| 226 allocated_buffers_[client_id].insert( |
| 227 std::make_pair(handle.id, buffer_info)); |
| 228 } |
141 std::move(callback).Run(handle); | 229 std::move(callback).Run(handle); |
142 } | 230 } |
143 | 231 |
144 } // namespace viz | 232 } // namespace viz |
OLD | NEW |