Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Side by Side Diff: content/common/gpu/client/context_provider_command_buffer.cc

Issue 2584363002: gpu: Move ContextProviderCommandBuffer into mus gpu client-lib. (Closed)
Patch Set: tot merge Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/common/gpu/client/context_provider_command_buffer.h"
6
7 #include <stddef.h>
8
9 #include <memory>
10 #include <set>
11 #include <utility>
12 #include <vector>
13
14 #include "base/callback_helpers.h"
15 #include "base/command_line.h"
16 #include "base/optional.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/threading/thread_task_runner_handle.h"
19 #include "base/trace_event/memory_dump_manager.h"
20 #include "cc/output/context_cache_controller.h"
21 #include "cc/output/managed_memory_policy.h"
22 #include "content/common/gpu/client/command_buffer_metrics.h"
23 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
24 #include "gpu/command_buffer/client/gles2_implementation.h"
25 #include "gpu/command_buffer/client/gles2_trace_implementation.h"
26 #include "gpu/command_buffer/client/gpu_switches.h"
27 #include "gpu/command_buffer/client/transfer_buffer.h"
28 #include "gpu/command_buffer/common/constants.h"
29 #include "gpu/ipc/client/command_buffer_proxy_impl.h"
30 #include "gpu/ipc/client/gpu_channel_host.h"
31 #include "gpu/skia_bindings/grcontext_for_gles2_interface.h"
32 #include "third_party/skia/include/core/SkTraceMemoryDump.h"
33 #include "third_party/skia/include/gpu/GrContext.h"
34 #include "ui/gl/trace_util.h"
35
36 class SkDiscardableMemory;
37
38 namespace {
39
40 // Similar to base::AutoReset but it sets the variable to the new value
41 // when it is destroyed. Use Reset() to cancel setting the variable.
42 class AutoSet {
43 public:
44 AutoSet(bool* b, bool set) : b_(b), set_(set) {}
45 ~AutoSet() {
46 if (b_)
47 *b_ = set_;
48 }
49 // Stops us from setting b_ on destruction.
50 void Reset() { b_ = nullptr; }
51
52 private:
53 bool* b_;
54 const bool set_;
55 };
56
57 // Derives from SkTraceMemoryDump and implements graphics specific memory
58 // backing functionality.
59 class SkiaGpuTraceMemoryDump : public SkTraceMemoryDump {
60 public:
61 // This should never outlive the provided ProcessMemoryDump, as it should
62 // always be scoped to a single OnMemoryDump funciton call.
63 explicit SkiaGpuTraceMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
64 uint64_t share_group_tracing_guid)
65 : pmd_(pmd), share_group_tracing_guid_(share_group_tracing_guid) {}
66
67 // Overridden from SkTraceMemoryDump:
68 void dumpNumericValue(const char* dump_name,
69 const char* value_name,
70 const char* units,
71 uint64_t value) override {
72 auto* dump = GetOrCreateAllocatorDump(dump_name);
73 dump->AddScalar(value_name, units, value);
74 }
75
76 void setMemoryBacking(const char* dump_name,
77 const char* backing_type,
78 const char* backing_object_id) override {
79 const uint64_t tracing_process_id =
80 base::trace_event::MemoryDumpManager::GetInstance()
81 ->GetTracingProcessId();
82
83 // For uniformity, skia provides this value as a string. Convert back to a
84 // uint32_t.
85 uint32_t gl_id =
86 std::strtoul(backing_object_id, nullptr /* str_end */, 10 /* base */);
87
88 // Constants used by SkiaGpuTraceMemoryDump to identify different memory
89 // types.
90 const char* kGLTextureBackingType = "gl_texture";
91 const char* kGLBufferBackingType = "gl_buffer";
92 const char* kGLRenderbufferBackingType = "gl_renderbuffer";
93
94 // Populated in if statements below.
95 base::trace_event::MemoryAllocatorDumpGuid guid;
96
97 if (strcmp(backing_type, kGLTextureBackingType) == 0) {
98 guid = gl::GetGLTextureClientGUIDForTracing(share_group_tracing_guid_,
99 gl_id);
100 } else if (strcmp(backing_type, kGLBufferBackingType) == 0) {
101 guid = gl::GetGLBufferGUIDForTracing(tracing_process_id, gl_id);
102 } else if (strcmp(backing_type, kGLRenderbufferBackingType) == 0) {
103 guid = gl::GetGLRenderbufferGUIDForTracing(tracing_process_id, gl_id);
104 }
105
106 if (!guid.empty()) {
107 pmd_->CreateSharedGlobalAllocatorDump(guid);
108
109 auto* dump = GetOrCreateAllocatorDump(dump_name);
110
111 const int kImportance = 2;
112 pmd_->AddOwnershipEdge(dump->guid(), guid, kImportance);
113 }
114 }
115
116 void setDiscardableMemoryBacking(
117 const char* dump_name,
118 const SkDiscardableMemory& discardable_memory_object) override {
119 // We don't use this class for dumping discardable memory.
120 NOTREACHED();
121 }
122
123 LevelOfDetail getRequestedDetails() const override {
124 // TODO(ssid): Use MemoryDumpArgs to create light dumps when requested
125 // (crbug.com/499731).
126 return kObjectsBreakdowns_LevelOfDetail;
127 }
128
129 private:
130 // Helper to create allocator dumps.
131 base::trace_event::MemoryAllocatorDump* GetOrCreateAllocatorDump(
132 const char* dump_name) {
133 auto* dump = pmd_->GetAllocatorDump(dump_name);
134 if (!dump)
135 dump = pmd_->CreateAllocatorDump(dump_name);
136 return dump;
137 }
138
139 base::trace_event::ProcessMemoryDump* pmd_;
140 uint64_t share_group_tracing_guid_;
141
142 DISALLOW_COPY_AND_ASSIGN(SkiaGpuTraceMemoryDump);
143 };
144
145 } // namespace
146
147 namespace content {
148
149 ContextProviderCommandBuffer::SharedProviders::SharedProviders() = default;
150 ContextProviderCommandBuffer::SharedProviders::~SharedProviders() = default;
151
152 ContextProviderCommandBuffer::ContextProviderCommandBuffer(
153 scoped_refptr<gpu::GpuChannelHost> channel,
154 int32_t stream_id,
155 gpu::GpuStreamPriority stream_priority,
156 gpu::SurfaceHandle surface_handle,
157 const GURL& active_url,
158 bool automatic_flushes,
159 bool support_locking,
160 const gpu::SharedMemoryLimits& memory_limits,
161 const gpu::gles2::ContextCreationAttribHelper& attributes,
162 ContextProviderCommandBuffer* shared_context_provider,
163 command_buffer_metrics::ContextType type)
164 : stream_id_(stream_id),
165 stream_priority_(stream_priority),
166 surface_handle_(surface_handle),
167 active_url_(active_url),
168 automatic_flushes_(automatic_flushes),
169 support_locking_(support_locking),
170 memory_limits_(memory_limits),
171 attributes_(attributes),
172 context_type_(type),
173 shared_providers_(shared_context_provider
174 ? shared_context_provider->shared_providers_
175 : new SharedProviders),
176 channel_(std::move(channel)) {
177 DCHECK(main_thread_checker_.CalledOnValidThread());
178 DCHECK(channel_);
179 context_thread_checker_.DetachFromThread();
180 }
181
182 ContextProviderCommandBuffer::~ContextProviderCommandBuffer() {
183 DCHECK(main_thread_checker_.CalledOnValidThread() ||
184 context_thread_checker_.CalledOnValidThread());
185
186 {
187 base::AutoLock hold(shared_providers_->lock);
188 auto it = std::find(shared_providers_->list.begin(),
189 shared_providers_->list.end(), this);
190 if (it != shared_providers_->list.end())
191 shared_providers_->list.erase(it);
192 }
193
194 if (bind_succeeded_) {
195 // Clear the lock to avoid DCHECKs that the lock is being held during
196 // shutdown.
197 command_buffer_->SetLock(nullptr);
198 // Disconnect lost callbacks during destruction.
199 gles2_impl_->SetLostContextCallback(base::Closure());
200 // Unregister memory dump provider.
201 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
202 this);
203 }
204 }
205
206 gpu::CommandBufferProxyImpl*
207 ContextProviderCommandBuffer::GetCommandBufferProxy() {
208 return command_buffer_.get();
209 }
210
211 uint32_t ContextProviderCommandBuffer::GetCopyTextureInternalFormat() {
212 if (attributes_.alpha_size > 0)
213 return GL_RGBA;
214 DCHECK_NE(attributes_.red_size, 0);
215 DCHECK_NE(attributes_.green_size, 0);
216 DCHECK_NE(attributes_.blue_size, 0);
217 return GL_RGB;
218 }
219
220 bool ContextProviderCommandBuffer::BindToCurrentThread() {
221 // This is called on the thread the context will be used.
222 DCHECK(context_thread_checker_.CalledOnValidThread());
223
224 if (bind_failed_)
225 return false;
226 if (bind_succeeded_)
227 return true;
228
229 // Early outs should report failure.
230 AutoSet set_bind_failed(&bind_failed_, true);
231
232 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
233 default_task_runner_;
234 if (!task_runner)
235 task_runner = base::ThreadTaskRunnerHandle::Get();
236
237 // It's possible to be running BindToCurrentThread on two contexts
238 // on different threads at the same time, but which will be in the same share
239 // group. To ensure they end up in the same group, hold the lock on the
240 // shared_providers_ (which they will share) after querying the group, until
241 // this context has been added to the list.
242 {
243 ContextProviderCommandBuffer* shared_context_provider = nullptr;
244 gpu::CommandBufferProxyImpl* shared_command_buffer = nullptr;
245 scoped_refptr<gpu::gles2::ShareGroup> share_group;
246
247 base::AutoLock hold(shared_providers_->lock);
248
249 if (!shared_providers_->list.empty()) {
250 shared_context_provider = shared_providers_->list.front();
251 shared_command_buffer = shared_context_provider->command_buffer_.get();
252 share_group = shared_context_provider->gles2_impl_->share_group();
253 DCHECK_EQ(!!shared_command_buffer, !!share_group);
254 }
255
256 // This command buffer is a client-side proxy to the command buffer in the
257 // GPU process.
258 command_buffer_ = gpu::CommandBufferProxyImpl::Create(
259 std::move(channel_), surface_handle_, shared_command_buffer, stream_id_,
260 stream_priority_, attributes_, active_url_, task_runner);
261 if (!command_buffer_) {
262 DLOG(ERROR) << "GpuChannelHost failed to create command buffer.";
263 command_buffer_metrics::UmaRecordContextInitFailed(context_type_);
264 return false;
265 }
266
267 // The GLES2 helper writes the command buffer protocol.
268 gles2_helper_.reset(new gpu::gles2::GLES2CmdHelper(command_buffer_.get()));
269 gles2_helper_->SetAutomaticFlushes(automatic_flushes_);
270 if (!gles2_helper_->Initialize(memory_limits_.command_buffer_size)) {
271 DLOG(ERROR) << "Failed to initialize GLES2CmdHelper.";
272 return false;
273 }
274
275 // The transfer buffer is used to copy resources between the client
276 // process and the GPU process.
277 transfer_buffer_.reset(new gpu::TransferBuffer(gles2_helper_.get()));
278
279 // The GLES2Implementation exposes the OpenGLES2 API, as well as the
280 // gpu::ContextSupport interface.
281 constexpr bool support_client_side_arrays = false;
282 gles2_impl_.reset(new gpu::gles2::GLES2Implementation(
283 gles2_helper_.get(), share_group, transfer_buffer_.get(),
284 attributes_.bind_generates_resource,
285 attributes_.lose_context_when_out_of_memory, support_client_side_arrays,
286 command_buffer_.get()));
287 if (!gles2_impl_->Initialize(memory_limits_.start_transfer_buffer_size,
288 memory_limits_.min_transfer_buffer_size,
289 memory_limits_.max_transfer_buffer_size,
290 memory_limits_.mapped_memory_reclaim_limit)) {
291 DLOG(ERROR) << "Failed to initialize GLES2Implementation.";
292 return false;
293 }
294
295 if (command_buffer_->GetLastState().error != gpu::error::kNoError) {
296 DLOG(ERROR) << "Context dead on arrival. Last error: "
297 << command_buffer_->GetLastState().error;
298 return false;
299 }
300
301 // If any context in the share group has been lost, then abort and don't
302 // continue since we need to go back to the caller of the constructor to
303 // find the correct share group.
304 // This may happen in between the share group being chosen at the
305 // constructor, and getting to run this BindToCurrentThread method which
306 // can be on some other thread.
307 // We intentionally call this *after* creating the command buffer via the
308 // GpuChannelHost. Once that has happened, the service knows we are in the
309 // share group and if a shared context is lost, our context will be informed
310 // also, and the lost context callback will occur for the owner of the
311 // context provider. If we check sooner, the shared context may be lost in
312 // between these two states and our context here would be left in an orphan
313 // share group.
314 if (share_group && share_group->IsLost())
315 return false;
316
317 shared_providers_->list.push_back(this);
318
319 cache_controller_.reset(
320 new cc::ContextCacheController(gles2_impl_.get(), task_runner));
321 }
322 set_bind_failed.Reset();
323 bind_succeeded_ = true;
324
325 gles2_impl_->SetLostContextCallback(
326 base::Bind(&ContextProviderCommandBuffer::OnLostContext,
327 // |this| owns the GLES2Implementation which holds the
328 // callback.
329 base::Unretained(this)));
330
331 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
332 switches::kEnableGpuClientTracing)) {
333 // This wraps the real GLES2Implementation and we should always use this
334 // instead when it's present.
335 trace_impl_.reset(
336 new gpu::gles2::GLES2TraceImplementation(gles2_impl_.get()));
337 }
338
339 // Do this last once the context is set up.
340 std::string type_name =
341 command_buffer_metrics::ContextTypeToString(context_type_);
342 std::string unique_context_name =
343 base::StringPrintf("%s-%p", type_name.c_str(), gles2_impl_.get());
344 ContextGL()->TraceBeginCHROMIUM("gpu_toplevel", unique_context_name.c_str());
345 // If support_locking_ is true, the context may be used from multiple
346 // threads, and any async callstacks will need to hold the same lock, so
347 // give it to the command buffer and cache controller.
348 // We don't hold a lock here since there's no need, so set the lock very last
349 // to prevent asserts that we're not holding it.
350 if (support_locking_) {
351 command_buffer_->SetLock(&context_lock_);
352 cache_controller_->SetLock(&context_lock_);
353 }
354 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
355 this, "ContextProviderCommandBuffer", std::move(task_runner));
356 return true;
357 }
358
359 void ContextProviderCommandBuffer::DetachFromThread() {
360 context_thread_checker_.DetachFromThread();
361 }
362
363 gpu::gles2::GLES2Interface* ContextProviderCommandBuffer::ContextGL() {
364 DCHECK(bind_succeeded_);
365 DCHECK(context_thread_checker_.CalledOnValidThread());
366
367 if (trace_impl_)
368 return trace_impl_.get();
369 return gles2_impl_.get();
370 }
371
372 gpu::ContextSupport* ContextProviderCommandBuffer::ContextSupport() {
373 return gles2_impl_.get();
374 }
375
376 class GrContext* ContextProviderCommandBuffer::GrContext() {
377 DCHECK(bind_succeeded_);
378 DCHECK(context_thread_checker_.CalledOnValidThread());
379
380 if (gr_context_)
381 return gr_context_->get();
382
383 gr_context_.reset(new skia_bindings::GrContextForGLES2Interface(ContextGL()));
384 cache_controller_->SetGrContext(gr_context_->get());
385
386 // If GlContext is already lost, also abandon the new GrContext.
387 if (gr_context_->get() &&
388 ContextGL()->GetGraphicsResetStatusKHR() != GL_NO_ERROR)
389 gr_context_->get()->abandonContext();
390
391 return gr_context_->get();
392 }
393
394 cc::ContextCacheController* ContextProviderCommandBuffer::CacheController() {
395 DCHECK(context_thread_checker_.CalledOnValidThread());
396 return cache_controller_.get();
397 }
398
399 void ContextProviderCommandBuffer::InvalidateGrContext(uint32_t state) {
400 if (gr_context_) {
401 DCHECK(bind_succeeded_);
402 DCHECK(context_thread_checker_.CalledOnValidThread());
403 gr_context_->ResetContext(state);
404 }
405 }
406
407 void ContextProviderCommandBuffer::SetDefaultTaskRunner(
408 scoped_refptr<base::SingleThreadTaskRunner> default_task_runner) {
409 DCHECK(!bind_succeeded_);
410 default_task_runner_ = std::move(default_task_runner);
411 }
412
413 base::Lock* ContextProviderCommandBuffer::GetLock() {
414 DCHECK(support_locking_);
415 return &context_lock_;
416 }
417
418 gpu::Capabilities ContextProviderCommandBuffer::ContextCapabilities() {
419 DCHECK(bind_succeeded_);
420 DCHECK(context_thread_checker_.CalledOnValidThread());
421 // Skips past the trace_impl_ as it doesn't have capabilities.
422 return gles2_impl_->capabilities();
423 }
424
425 void ContextProviderCommandBuffer::OnLostContext() {
426 DCHECK(context_thread_checker_.CalledOnValidThread());
427
428 if (!lost_context_callback_.is_null())
429 lost_context_callback_.Run();
430 if (gr_context_)
431 gr_context_->OnLostContext();
432
433 gpu::CommandBuffer::State state = GetCommandBufferProxy()->GetLastState();
434 command_buffer_metrics::UmaRecordContextLost(context_type_, state.error,
435 state.context_lost_reason);
436 }
437
438 void ContextProviderCommandBuffer::SetLostContextCallback(
439 const LostContextCallback& lost_context_callback) {
440 DCHECK(context_thread_checker_.CalledOnValidThread());
441 DCHECK(lost_context_callback_.is_null() ||
442 lost_context_callback.is_null());
443 lost_context_callback_ = lost_context_callback;
444 }
445
446 bool ContextProviderCommandBuffer::OnMemoryDump(
447 const base::trace_event::MemoryDumpArgs& args,
448 base::trace_event::ProcessMemoryDump* pmd) {
449 DCHECK(bind_succeeded_);
450
451 base::Optional<base::AutoLock> hold;
452 if (support_locking_)
453 hold.emplace(context_lock_);
454
455 gles2_impl_->OnMemoryDump(args, pmd);
456 gles2_helper_->OnMemoryDump(args, pmd);
457
458 if (gr_context_) {
459 context_thread_checker_.DetachFromThread();
460 SkiaGpuTraceMemoryDump trace_memory_dump(
461 pmd, gles2_impl_->ShareGroupTracingGUID());
462 gr_context_->get()->dumpMemoryStatistics(&trace_memory_dump);
463 context_thread_checker_.DetachFromThread();
464 }
465 return true;
466 }
467
468 } // namespace content
OLDNEW
« no previous file with comments | « content/common/gpu/client/context_provider_command_buffer.h ('k') | content/renderer/child_frame_compositing_helper.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698