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

Side by Side Diff: content/common/gpu/gpu_command_buffer_stub.cc

Issue 1845563005: Refactor content/common/gpu into gpu/ipc/service (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Drop ref to deleted content_tests_gypi_values.content_unittests_ozone_sources Created 4 years, 8 months 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
« no previous file with comments | « content/common/gpu/gpu_command_buffer_stub.h ('k') | content/common/gpu/gpu_config.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 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/gpu_command_buffer_stub.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/hash.h"
12 #include "base/json/json_writer.h"
13 #include "base/macros.h"
14 #include "base/memory/shared_memory.h"
15 #include "base/time/time.h"
16 #include "base/trace_event/trace_event.h"
17 #include "build/build_config.h"
18 #include "content/common/gpu/gpu_channel.h"
19 #include "content/common/gpu/gpu_channel_manager.h"
20 #include "content/common/gpu/gpu_channel_manager_delegate.h"
21 #include "content/common/gpu/gpu_memory_manager.h"
22 #include "content/common/gpu/gpu_memory_tracking.h"
23 #include "content/common/gpu/gpu_watchdog.h"
24 #include "content/common/gpu/image_transport_surface.h"
25 #include "gpu/command_buffer/common/constants.h"
26 #include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
27 #include "gpu/command_buffer/common/mailbox.h"
28 #include "gpu/command_buffer/common/sync_token.h"
29 #include "gpu/command_buffer/service/gl_context_virtual.h"
30 #include "gpu/command_buffer/service/gl_state_restorer_impl.h"
31 #include "gpu/command_buffer/service/image_manager.h"
32 #include "gpu/command_buffer/service/logger.h"
33 #include "gpu/command_buffer/service/mailbox_manager.h"
34 #include "gpu/command_buffer/service/memory_tracking.h"
35 #include "gpu/command_buffer/service/query_manager.h"
36 #include "gpu/command_buffer/service/sync_point_manager.h"
37 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
38 #include "gpu/command_buffer/service/valuebuffer_manager.h"
39 #include "gpu/ipc/common/gpu_messages.h"
40 #include "ui/gl/gl_bindings.h"
41 #include "ui/gl/gl_image.h"
42 #include "ui/gl/gl_switches.h"
43
44 #if defined(OS_WIN)
45 #include "base/win/win_util.h"
46 #endif
47
48 #if defined(OS_ANDROID)
49 #include "content/common/gpu/stream_texture_android.h"
50 #endif
51
52 namespace content {
53 struct WaitForCommandState {
54 WaitForCommandState(int32_t start, int32_t end, IPC::Message* reply)
55 : start(start), end(end), reply(reply) {}
56
57 int32_t start;
58 int32_t end;
59 scoped_ptr<IPC::Message> reply;
60 };
61
62 namespace {
63
64 // The GpuCommandBufferMemoryTracker class provides a bridge between the
65 // ContextGroup's memory type managers and the GpuMemoryManager class.
66 class GpuCommandBufferMemoryTracker : public gpu::gles2::MemoryTracker {
67 public:
68 explicit GpuCommandBufferMemoryTracker(GpuChannel* channel,
69 uint64_t share_group_tracing_guid)
70 : tracking_group_(
71 channel->gpu_channel_manager()
72 ->gpu_memory_manager()
73 ->CreateTrackingGroup(channel->GetClientPID(), this)),
74 client_tracing_id_(channel->client_tracing_id()),
75 client_id_(channel->client_id()),
76 share_group_tracing_guid_(share_group_tracing_guid) {}
77
78 void TrackMemoryAllocatedChange(
79 size_t old_size, size_t new_size) override {
80 tracking_group_->TrackMemoryAllocatedChange(
81 old_size, new_size);
82 }
83
84 bool EnsureGPUMemoryAvailable(size_t size_needed) override {
85 return tracking_group_->EnsureGPUMemoryAvailable(size_needed);
86 };
87
88 uint64_t ClientTracingId() const override { return client_tracing_id_; }
89 int ClientId() const override { return client_id_; }
90 uint64_t ShareGroupTracingGUID() const override {
91 return share_group_tracing_guid_;
92 }
93
94 private:
95 ~GpuCommandBufferMemoryTracker() override {}
96 scoped_ptr<GpuMemoryTrackingGroup> tracking_group_;
97 const uint64_t client_tracing_id_;
98 const int client_id_;
99 const uint64_t share_group_tracing_guid_;
100
101 DISALLOW_COPY_AND_ASSIGN(GpuCommandBufferMemoryTracker);
102 };
103
104 // FastSetActiveURL will shortcut the expensive call to SetActiveURL when the
105 // url_hash matches.
106 void FastSetActiveURL(const GURL& url, size_t url_hash, GpuChannel* channel) {
107 // Leave the previously set URL in the empty case -- empty URLs are given by
108 // BlinkPlatformImpl::createOffscreenGraphicsContext3DProvider. Hopefully the
109 // onscreen context URL was set previously and will show up even when a crash
110 // occurs during offscreen command processing.
111 if (url.is_empty())
112 return;
113 static size_t g_last_url_hash = 0;
114 if (url_hash != g_last_url_hash) {
115 g_last_url_hash = url_hash;
116 DCHECK(channel && channel->gpu_channel_manager() &&
117 channel->gpu_channel_manager()->delegate());
118 channel->gpu_channel_manager()->delegate()->SetActiveURL(url);
119 }
120 }
121
122 // The first time polling a fence, delay some extra time to allow other
123 // stubs to process some work, or else the timing of the fences could
124 // allow a pattern of alternating fast and slow frames to occur.
125 const int64_t kHandleMoreWorkPeriodMs = 2;
126 const int64_t kHandleMoreWorkPeriodBusyMs = 1;
127
128 // Prevents idle work from being starved.
129 const int64_t kMaxTimeSinceIdleMs = 10;
130
131 class DevToolsChannelData : public base::trace_event::ConvertableToTraceFormat {
132 public:
133 static scoped_ptr<base::trace_event::ConvertableToTraceFormat>
134 CreateForChannel(GpuChannel* channel);
135 ~DevToolsChannelData() override {}
136
137 void AppendAsTraceFormat(std::string* out) const override {
138 std::string tmp;
139 base::JSONWriter::Write(*value_, &tmp);
140 *out += tmp;
141 }
142
143 private:
144 explicit DevToolsChannelData(base::Value* value) : value_(value) {}
145 scoped_ptr<base::Value> value_;
146 DISALLOW_COPY_AND_ASSIGN(DevToolsChannelData);
147 };
148
149 scoped_ptr<base::trace_event::ConvertableToTraceFormat>
150 DevToolsChannelData::CreateForChannel(GpuChannel* channel) {
151 scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue);
152 res->SetInteger("renderer_pid", channel->GetClientPID());
153 res->SetDouble("used_bytes", channel->GetMemoryUsage());
154 return make_scoped_ptr(new DevToolsChannelData(res.release()));
155 }
156
157 gpu::CommandBufferId GetCommandBufferID(int channel_id, int32_t route_id) {
158 return gpu::CommandBufferId::FromUnsafeValue(
159 (static_cast<uint64_t>(channel_id) << 32) | route_id);
160 }
161
162 } // namespace
163
164 GpuCommandBufferStub::GpuCommandBufferStub(
165 GpuChannel* channel,
166 gpu::SyncPointManager* sync_point_manager,
167 base::SingleThreadTaskRunner* task_runner,
168 GpuCommandBufferStub* share_group,
169 gpu::SurfaceHandle surface_handle,
170 gpu::gles2::MailboxManager* mailbox_manager,
171 gpu::PreemptionFlag* preempt_by_flag,
172 gpu::gles2::SubscriptionRefSet* subscription_ref_set,
173 gpu::ValueStateMap* pending_valuebuffer_state,
174 const gfx::Size& size,
175 const gpu::gles2::DisallowedFeatures& disallowed_features,
176 const std::vector<int32_t>& attribs,
177 gfx::GpuPreference gpu_preference,
178 int32_t stream_id,
179 int32_t route_id,
180 GpuWatchdog* watchdog,
181 const GURL& active_url)
182 : channel_(channel),
183 sync_point_manager_(sync_point_manager),
184 task_runner_(task_runner),
185 initialized_(false),
186 surface_handle_(surface_handle),
187 initial_size_(size),
188 disallowed_features_(disallowed_features),
189 requested_attribs_(attribs),
190 gpu_preference_(gpu_preference),
191 use_virtualized_gl_context_(false),
192 command_buffer_id_(GetCommandBufferID(channel->client_id(), route_id)),
193 stream_id_(stream_id),
194 route_id_(route_id),
195 last_flush_count_(0),
196 surface_format_(gfx::GLSurface::SURFACE_DEFAULT),
197 watchdog_(watchdog),
198 waiting_for_sync_point_(false),
199 previous_processed_num_(0),
200 preemption_flag_(preempt_by_flag),
201 active_url_(active_url) {
202 active_url_hash_ = base::Hash(active_url.possibly_invalid_spec());
203 FastSetActiveURL(active_url_, active_url_hash_, channel_);
204
205 gpu::gles2::ContextCreationAttribHelper attrib_parser;
206 attrib_parser.Parse(requested_attribs_);
207
208 if (share_group) {
209 context_group_ = share_group->context_group_;
210 DCHECK(context_group_->bind_generates_resource() ==
211 attrib_parser.bind_generates_resource);
212 } else {
213 context_group_ = new gpu::gles2::ContextGroup(
214 channel_->gpu_channel_manager()->gpu_preferences(), mailbox_manager,
215 new GpuCommandBufferMemoryTracker(channel,
216 command_buffer_id_.GetUnsafeValue()),
217 channel_->gpu_channel_manager()->shader_translator_cache(),
218 channel_->gpu_channel_manager()->framebuffer_completeness_cache(), NULL,
219 subscription_ref_set, pending_valuebuffer_state,
220 attrib_parser.bind_generates_resource);
221 }
222
223 // Virtualize PreferIntegratedGpu contexts by default on OS X to prevent
224 // performance regressions when enabling FCM.
225 // http://crbug.com/180463
226 #if defined(OS_MACOSX)
227 if (gpu_preference_ == gfx::PreferIntegratedGpu)
228 use_virtualized_gl_context_ = true;
229 #endif
230
231 use_virtualized_gl_context_ |=
232 context_group_->feature_info()->workarounds().use_virtualized_gl_contexts;
233
234 // MailboxManagerSync synchronization correctness currently depends on having
235 // only a single context. See crbug.com/510243 for details.
236 use_virtualized_gl_context_ |= mailbox_manager->UsesSync();
237
238 #if defined(OS_ANDROID)
239 if (attrib_parser.red_size <= 5 &&
240 attrib_parser.green_size <= 6 &&
241 attrib_parser.blue_size <= 5 &&
242 attrib_parser.alpha_size == 0)
243 surface_format_ = gfx::GLSurface::SURFACE_RGB565;
244 gfx::GLSurface* defaultOffscreenSurface =
245 channel_->gpu_channel_manager()->GetDefaultOffscreenSurface();
246 bool is_onscreen = (surface_handle_ != gpu::kNullSurfaceHandle);
247 if (surface_format_ != defaultOffscreenSurface->GetFormat() && is_onscreen)
248 use_virtualized_gl_context_ = false;
249 #endif
250
251 if ((surface_handle_ == gpu::kNullSurfaceHandle) && initial_size_.IsEmpty()) {
252 // If we're an offscreen surface with zero width and/or height, set to a
253 // non-zero size so that we have a complete framebuffer for operations like
254 // glClear.
255 initial_size_ = gfx::Size(1, 1);
256 }
257 }
258
259 GpuCommandBufferStub::~GpuCommandBufferStub() {
260 Destroy();
261 }
262
263 GpuMemoryManager* GpuCommandBufferStub::GetMemoryManager() const {
264 return channel()->gpu_channel_manager()->gpu_memory_manager();
265 }
266
267 bool GpuCommandBufferStub::OnMessageReceived(const IPC::Message& message) {
268 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
269 "GPUTask",
270 "data",
271 DevToolsChannelData::CreateForChannel(channel()));
272 FastSetActiveURL(active_url_, active_url_hash_, channel_);
273
274 bool have_context = false;
275 // Ensure the appropriate GL context is current before handling any IPC
276 // messages directed at the command buffer. This ensures that the message
277 // handler can assume that the context is current (not necessary for
278 // RetireSyncPoint or WaitSyncPoint).
279 if (decoder_.get() &&
280 message.type() != GpuCommandBufferMsg_SetGetBuffer::ID &&
281 message.type() != GpuCommandBufferMsg_WaitForTokenInRange::ID &&
282 message.type() != GpuCommandBufferMsg_WaitForGetOffsetInRange::ID &&
283 message.type() != GpuCommandBufferMsg_RegisterTransferBuffer::ID &&
284 message.type() != GpuCommandBufferMsg_DestroyTransferBuffer::ID) {
285 if (!MakeCurrent())
286 return false;
287 have_context = true;
288 }
289
290 // Always use IPC_MESSAGE_HANDLER_DELAY_REPLY for synchronous message handlers
291 // here. This is so the reply can be delayed if the scheduler is unscheduled.
292 bool handled = true;
293 IPC_BEGIN_MESSAGE_MAP(GpuCommandBufferStub, message)
294 IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuCommandBufferMsg_Initialize,
295 OnInitialize);
296 IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuCommandBufferMsg_SetGetBuffer,
297 OnSetGetBuffer);
298 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_ProduceFrontBuffer,
299 OnProduceFrontBuffer);
300 IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuCommandBufferMsg_WaitForTokenInRange,
301 OnWaitForTokenInRange);
302 IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuCommandBufferMsg_WaitForGetOffsetInRange,
303 OnWaitForGetOffsetInRange);
304 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_AsyncFlush, OnAsyncFlush);
305 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_RegisterTransferBuffer,
306 OnRegisterTransferBuffer);
307 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_DestroyTransferBuffer,
308 OnDestroyTransferBuffer);
309 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SignalSyncToken,
310 OnSignalSyncToken)
311 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SignalQuery,
312 OnSignalQuery)
313 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_CreateImage, OnCreateImage);
314 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_DestroyImage, OnDestroyImage);
315 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_CreateStreamTexture,
316 OnCreateStreamTexture)
317 IPC_MESSAGE_UNHANDLED(handled = false)
318 IPC_END_MESSAGE_MAP()
319
320 CheckCompleteWaits();
321
322 // Ensure that any delayed work that was created will be handled.
323 if (have_context) {
324 if (executor_)
325 executor_->ProcessPendingQueries();
326 ScheduleDelayedWork(
327 base::TimeDelta::FromMilliseconds(kHandleMoreWorkPeriodMs));
328 }
329
330 return handled;
331 }
332
333 bool GpuCommandBufferStub::Send(IPC::Message* message) {
334 return channel_->Send(message);
335 }
336
337 bool GpuCommandBufferStub::IsScheduled() {
338 return (!executor_.get() || executor_->scheduled());
339 }
340
341 void GpuCommandBufferStub::PollWork() {
342 // Post another delayed task if we have not yet reached the time at which
343 // we should process delayed work.
344 base::TimeTicks current_time = base::TimeTicks::Now();
345 DCHECK(!process_delayed_work_time_.is_null());
346 if (process_delayed_work_time_ > current_time) {
347 task_runner_->PostDelayedTask(
348 FROM_HERE, base::Bind(&GpuCommandBufferStub::PollWork, AsWeakPtr()),
349 process_delayed_work_time_ - current_time);
350 return;
351 }
352 process_delayed_work_time_ = base::TimeTicks();
353
354 PerformWork();
355 }
356
357 void GpuCommandBufferStub::PerformWork() {
358 TRACE_EVENT0("gpu", "GpuCommandBufferStub::PerformWork");
359
360 FastSetActiveURL(active_url_, active_url_hash_, channel_);
361 if (decoder_.get() && !MakeCurrent())
362 return;
363
364 if (executor_) {
365 uint32_t current_unprocessed_num =
366 channel()->gpu_channel_manager()->GetUnprocessedOrderNum();
367 // We're idle when no messages were processed or scheduled.
368 bool is_idle = (previous_processed_num_ == current_unprocessed_num);
369 if (!is_idle && !last_idle_time_.is_null()) {
370 base::TimeDelta time_since_idle =
371 base::TimeTicks::Now() - last_idle_time_;
372 base::TimeDelta max_time_since_idle =
373 base::TimeDelta::FromMilliseconds(kMaxTimeSinceIdleMs);
374
375 // Force idle when it's been too long since last time we were idle.
376 if (time_since_idle > max_time_since_idle)
377 is_idle = true;
378 }
379
380 if (is_idle) {
381 last_idle_time_ = base::TimeTicks::Now();
382 executor_->PerformIdleWork();
383 }
384
385 executor_->ProcessPendingQueries();
386 }
387
388 ScheduleDelayedWork(
389 base::TimeDelta::FromMilliseconds(kHandleMoreWorkPeriodBusyMs));
390 }
391
392 bool GpuCommandBufferStub::HasUnprocessedCommands() {
393 if (command_buffer_) {
394 gpu::CommandBuffer::State state = command_buffer_->GetLastState();
395 return command_buffer_->GetPutOffset() != state.get_offset &&
396 !gpu::error::IsError(state.error);
397 }
398 return false;
399 }
400
401 void GpuCommandBufferStub::ScheduleDelayedWork(base::TimeDelta delay) {
402 bool has_more_work = executor_.get() && (executor_->HasPendingQueries() ||
403 executor_->HasMoreIdleWork());
404 if (!has_more_work) {
405 last_idle_time_ = base::TimeTicks();
406 return;
407 }
408
409 base::TimeTicks current_time = base::TimeTicks::Now();
410 // |process_delayed_work_time_| is set if processing of delayed work is
411 // already scheduled. Just update the time if already scheduled.
412 if (!process_delayed_work_time_.is_null()) {
413 process_delayed_work_time_ = current_time + delay;
414 return;
415 }
416
417 // Idle when no messages are processed between now and when
418 // PollWork is called.
419 previous_processed_num_ =
420 channel()->gpu_channel_manager()->GetProcessedOrderNum();
421 if (last_idle_time_.is_null())
422 last_idle_time_ = current_time;
423
424 // IsScheduled() returns true after passing all unschedule fences
425 // and this is when we can start performing idle work. Idle work
426 // is done synchronously so we can set delay to 0 and instead poll
427 // for more work at the rate idle work is performed. This also ensures
428 // that idle work is done as efficiently as possible without any
429 // unnecessary delays.
430 if (executor_.get() && executor_->scheduled() &&
431 executor_->HasMoreIdleWork()) {
432 delay = base::TimeDelta();
433 }
434
435 process_delayed_work_time_ = current_time + delay;
436 task_runner_->PostDelayedTask(
437 FROM_HERE, base::Bind(&GpuCommandBufferStub::PollWork, AsWeakPtr()),
438 delay);
439 }
440
441 bool GpuCommandBufferStub::MakeCurrent() {
442 if (decoder_->MakeCurrent())
443 return true;
444 DLOG(ERROR) << "Context lost because MakeCurrent failed.";
445 command_buffer_->SetContextLostReason(decoder_->GetContextLostReason());
446 command_buffer_->SetParseError(gpu::error::kLostContext);
447 CheckContextLost();
448 return false;
449 }
450
451 void GpuCommandBufferStub::Destroy() {
452 if (wait_for_token_) {
453 Send(wait_for_token_->reply.release());
454 wait_for_token_.reset();
455 }
456 if (wait_for_get_offset_) {
457 Send(wait_for_get_offset_->reply.release());
458 wait_for_get_offset_.reset();
459 }
460
461 if (initialized_) {
462 GpuChannelManager* gpu_channel_manager = channel_->gpu_channel_manager();
463 if ((surface_handle_ == gpu::kNullSurfaceHandle) && !active_url_.is_empty())
464 gpu_channel_manager->delegate()->DidDestroyOffscreenContext(active_url_);
465 }
466
467 if (decoder_)
468 decoder_->set_engine(NULL);
469
470 // The scheduler has raw references to the decoder and the command buffer so
471 // destroy it before those.
472 executor_.reset();
473
474 sync_point_client_.reset();
475
476 bool have_context = false;
477 if (decoder_ && decoder_->GetGLContext()) {
478 // Try to make the context current regardless of whether it was lost, so we
479 // don't leak resources.
480 have_context = decoder_->GetGLContext()->MakeCurrent(surface_.get());
481 }
482 FOR_EACH_OBSERVER(DestructionObserver,
483 destruction_observers_,
484 OnWillDestroyStub());
485
486 if (decoder_) {
487 decoder_->Destroy(have_context);
488 decoder_.reset();
489 }
490
491 command_buffer_.reset();
492
493 // Remove this after crbug.com/248395 is sorted out.
494 surface_ = NULL;
495 }
496
497 void GpuCommandBufferStub::OnInitializeFailed(IPC::Message* reply_message) {
498 Destroy();
499 GpuCommandBufferMsg_Initialize::WriteReplyParams(
500 reply_message, false, gpu::Capabilities());
501 Send(reply_message);
502 }
503
504 scoped_refptr<gfx::GLSurface> GpuCommandBufferStub::CreateSurface() {
505 GpuChannelManager* manager = channel_->gpu_channel_manager();
506 scoped_refptr<gfx::GLSurface> surface;
507 if (surface_handle_ != gpu::kNullSurfaceHandle) {
508 surface = ImageTransportSurface::CreateNativeSurface(
509 manager, this, surface_handle_, surface_format_);
510 if (!surface || !surface->Initialize(surface_format_))
511 return nullptr;
512 } else {
513 surface = manager->GetDefaultOffscreenSurface();
514 }
515 return surface;
516 }
517
518 void GpuCommandBufferStub::OnInitialize(
519 base::SharedMemoryHandle shared_state_handle,
520 IPC::Message* reply_message) {
521 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnInitialize");
522 DCHECK(!command_buffer_.get());
523
524 scoped_ptr<base::SharedMemory> shared_state_shm(
525 new base::SharedMemory(shared_state_handle, false));
526
527 command_buffer_.reset(new gpu::CommandBufferService(
528 context_group_->transfer_buffer_manager()));
529
530 bool result = command_buffer_->Initialize();
531 DCHECK(result);
532
533 GpuChannelManager* manager = channel_->gpu_channel_manager();
534 DCHECK(manager);
535
536 decoder_.reset(::gpu::gles2::GLES2Decoder::Create(context_group_.get()));
537 executor_.reset(new gpu::CommandExecutor(command_buffer_.get(),
538 decoder_.get(), decoder_.get()));
539 sync_point_client_ = sync_point_manager_->CreateSyncPointClient(
540 channel_->GetSyncPointOrderData(stream_id_),
541 gpu::CommandBufferNamespace::GPU_IO, command_buffer_id_);
542
543 if (preemption_flag_.get())
544 executor_->SetPreemptByFlag(preemption_flag_);
545
546 decoder_->set_engine(executor_.get());
547
548 surface_ = CreateSurface();
549 if (!surface_.get()) {
550 DLOG(ERROR) << "Failed to create surface.";
551 OnInitializeFailed(reply_message);
552 return;
553 }
554
555 scoped_refptr<gfx::GLContext> context;
556 gfx::GLShareGroup* share_group = channel_->share_group();
557 if (use_virtualized_gl_context_ && share_group) {
558 context = share_group->GetSharedContext();
559 if (!context.get()) {
560 context = gfx::GLContext::CreateGLContext(
561 channel_->share_group(),
562 channel_->gpu_channel_manager()->GetDefaultOffscreenSurface(),
563 gpu_preference_);
564 if (!context.get()) {
565 DLOG(ERROR) << "Failed to create shared context for virtualization.";
566 OnInitializeFailed(reply_message);
567 return;
568 }
569 channel_->share_group()->SetSharedContext(context.get());
570 }
571 // This should be a non-virtual GL context.
572 DCHECK(context->GetHandle());
573 context = new gpu::GLContextVirtual(
574 share_group, context.get(), decoder_->AsWeakPtr());
575 if (!context->Initialize(surface_.get(), gpu_preference_)) {
576 // The real context created above for the default offscreen surface
577 // might not be compatible with this surface.
578 context = NULL;
579
580 DLOG(ERROR) << "Failed to initialize virtual GL context.";
581 OnInitializeFailed(reply_message);
582 return;
583 }
584 }
585 if (!context.get()) {
586 context = gfx::GLContext::CreateGLContext(
587 share_group, surface_.get(), gpu_preference_);
588 }
589 if (!context.get()) {
590 DLOG(ERROR) << "Failed to create context.";
591 OnInitializeFailed(reply_message);
592 return;
593 }
594
595 if (!context->MakeCurrent(surface_.get())) {
596 LOG(ERROR) << "Failed to make context current.";
597 OnInitializeFailed(reply_message);
598 return;
599 }
600
601 if (!context->GetGLStateRestorer()) {
602 context->SetGLStateRestorer(
603 new gpu::GLStateRestorerImpl(decoder_->AsWeakPtr()));
604 }
605
606 if (!context_group_->has_program_cache() &&
607 !context_group_->feature_info()->workarounds().disable_program_cache) {
608 context_group_->set_program_cache(
609 channel_->gpu_channel_manager()->program_cache());
610 }
611
612 // Initialize the decoder with either the view or pbuffer GLContext.
613 bool offscreen = (surface_handle_ == gpu::kNullSurfaceHandle);
614 if (!decoder_->Initialize(surface_, context, offscreen, initial_size_,
615 disallowed_features_, requested_attribs_)) {
616 DLOG(ERROR) << "Failed to initialize decoder.";
617 OnInitializeFailed(reply_message);
618 return;
619 }
620
621 if (channel_->gpu_channel_manager()->
622 gpu_preferences().enable_gpu_service_logging) {
623 decoder_->set_log_commands(true);
624 }
625
626 decoder_->GetLogger()->SetMsgCallback(
627 base::Bind(&GpuCommandBufferStub::SendConsoleMessage,
628 base::Unretained(this)));
629 decoder_->SetShaderCacheCallback(
630 base::Bind(&GpuCommandBufferStub::SendCachedShader,
631 base::Unretained(this)));
632 decoder_->SetFenceSyncReleaseCallback(base::Bind(
633 &GpuCommandBufferStub::OnFenceSyncRelease, base::Unretained(this)));
634 decoder_->SetWaitFenceSyncCallback(base::Bind(
635 &GpuCommandBufferStub::OnWaitFenceSync, base::Unretained(this)));
636
637 command_buffer_->SetPutOffsetChangeCallback(
638 base::Bind(&GpuCommandBufferStub::PutChanged, base::Unretained(this)));
639 command_buffer_->SetGetBufferChangeCallback(base::Bind(
640 &gpu::CommandExecutor::SetGetBuffer, base::Unretained(executor_.get())));
641 command_buffer_->SetParseErrorCallback(
642 base::Bind(&GpuCommandBufferStub::OnParseError, base::Unretained(this)));
643 executor_->SetSchedulingChangedCallback(base::Bind(
644 &GpuCommandBufferStub::OnSchedulingChanged, base::Unretained(this)));
645
646 if (watchdog_) {
647 executor_->SetCommandProcessedCallback(base::Bind(
648 &GpuCommandBufferStub::OnCommandProcessed, base::Unretained(this)));
649 }
650
651 const size_t kSharedStateSize = sizeof(gpu::CommandBufferSharedState);
652 if (!shared_state_shm->Map(kSharedStateSize)) {
653 DLOG(ERROR) << "Failed to map shared state buffer.";
654 OnInitializeFailed(reply_message);
655 return;
656 }
657 command_buffer_->SetSharedStateBuffer(gpu::MakeBackingFromSharedMemory(
658 std::move(shared_state_shm), kSharedStateSize));
659
660 gpu::Capabilities capabilities = decoder_->GetCapabilities();
661
662 GpuCommandBufferMsg_Initialize::WriteReplyParams(
663 reply_message, true, capabilities);
664 Send(reply_message);
665
666 if ((surface_handle_ == gpu::kNullSurfaceHandle) && !active_url_.is_empty())
667 manager->delegate()->DidCreateOffscreenContext(active_url_);
668
669 initialized_ = true;
670 }
671
672 void GpuCommandBufferStub::OnCreateStreamTexture(uint32_t texture_id,
673 int32_t stream_id,
674 bool* succeeded) {
675 #if defined(OS_ANDROID)
676 *succeeded = StreamTexture::Create(this, texture_id, stream_id);
677 #else
678 *succeeded = false;
679 #endif
680 }
681
682 void GpuCommandBufferStub::SetLatencyInfoCallback(
683 const LatencyInfoCallback& callback) {
684 latency_info_callback_ = callback;
685 }
686
687 int32_t GpuCommandBufferStub::GetRequestedAttribute(int attr) const {
688 // The command buffer is pairs of enum, value
689 // search for the requested attribute, return the value.
690 for (std::vector<int32_t>::const_iterator it = requested_attribs_.begin();
691 it != requested_attribs_.end(); ++it) {
692 if (*it++ == attr) {
693 return *it;
694 }
695 }
696 return -1;
697 }
698
699 void GpuCommandBufferStub::OnSetGetBuffer(int32_t shm_id,
700 IPC::Message* reply_message) {
701 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnSetGetBuffer");
702 if (command_buffer_)
703 command_buffer_->SetGetBuffer(shm_id);
704 Send(reply_message);
705 }
706
707 void GpuCommandBufferStub::OnProduceFrontBuffer(const gpu::Mailbox& mailbox) {
708 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnProduceFrontBuffer");
709 if (!decoder_) {
710 LOG(ERROR) << "Can't produce front buffer before initialization.";
711 return;
712 }
713
714 decoder_->ProduceFrontBuffer(mailbox);
715 }
716
717 void GpuCommandBufferStub::OnParseError() {
718 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnParseError");
719 DCHECK(command_buffer_.get());
720 gpu::CommandBuffer::State state = command_buffer_->GetLastState();
721 IPC::Message* msg = new GpuCommandBufferMsg_Destroyed(
722 route_id_, state.context_lost_reason, state.error);
723 msg->set_unblock(true);
724 Send(msg);
725
726 // Tell the browser about this context loss as well, so it can
727 // determine whether client APIs like WebGL need to be immediately
728 // blocked from automatically running.
729 GpuChannelManager* gpu_channel_manager = channel_->gpu_channel_manager();
730 gpu_channel_manager->delegate()->DidLoseContext(
731 (surface_handle_ == gpu::kNullSurfaceHandle), state.context_lost_reason,
732 active_url_);
733
734 CheckContextLost();
735 }
736
737 void GpuCommandBufferStub::OnSchedulingChanged(bool scheduled) {
738 TRACE_EVENT1("gpu", "GpuCommandBufferStub::OnSchedulingChanged", "scheduled",
739 scheduled);
740 channel_->OnStreamRescheduled(stream_id_, scheduled);
741 }
742
743 void GpuCommandBufferStub::OnWaitForTokenInRange(int32_t start,
744 int32_t end,
745 IPC::Message* reply_message) {
746 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnWaitForTokenInRange");
747 DCHECK(command_buffer_.get());
748 CheckContextLost();
749 if (wait_for_token_)
750 LOG(ERROR) << "Got WaitForToken command while currently waiting for token.";
751 wait_for_token_ =
752 make_scoped_ptr(new WaitForCommandState(start, end, reply_message));
753 CheckCompleteWaits();
754 }
755
756 void GpuCommandBufferStub::OnWaitForGetOffsetInRange(
757 int32_t start,
758 int32_t end,
759 IPC::Message* reply_message) {
760 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnWaitForGetOffsetInRange");
761 DCHECK(command_buffer_.get());
762 CheckContextLost();
763 if (wait_for_get_offset_) {
764 LOG(ERROR)
765 << "Got WaitForGetOffset command while currently waiting for offset.";
766 }
767 wait_for_get_offset_ =
768 make_scoped_ptr(new WaitForCommandState(start, end, reply_message));
769 CheckCompleteWaits();
770 }
771
772 void GpuCommandBufferStub::CheckCompleteWaits() {
773 if (wait_for_token_ || wait_for_get_offset_) {
774 gpu::CommandBuffer::State state = command_buffer_->GetLastState();
775 if (wait_for_token_ &&
776 (gpu::CommandBuffer::InRange(
777 wait_for_token_->start, wait_for_token_->end, state.token) ||
778 state.error != gpu::error::kNoError)) {
779 ReportState();
780 GpuCommandBufferMsg_WaitForTokenInRange::WriteReplyParams(
781 wait_for_token_->reply.get(), state);
782 Send(wait_for_token_->reply.release());
783 wait_for_token_.reset();
784 }
785 if (wait_for_get_offset_ &&
786 (gpu::CommandBuffer::InRange(wait_for_get_offset_->start,
787 wait_for_get_offset_->end,
788 state.get_offset) ||
789 state.error != gpu::error::kNoError)) {
790 ReportState();
791 GpuCommandBufferMsg_WaitForGetOffsetInRange::WriteReplyParams(
792 wait_for_get_offset_->reply.get(), state);
793 Send(wait_for_get_offset_->reply.release());
794 wait_for_get_offset_.reset();
795 }
796 }
797 }
798
799 void GpuCommandBufferStub::OnAsyncFlush(
800 int32_t put_offset,
801 uint32_t flush_count,
802 const std::vector<ui::LatencyInfo>& latency_info) {
803 TRACE_EVENT1(
804 "gpu", "GpuCommandBufferStub::OnAsyncFlush", "put_offset", put_offset);
805 DCHECK(command_buffer_);
806
807 // We received this message out-of-order. This should not happen but is here
808 // to catch regressions. Ignore the message.
809 DVLOG_IF(0, flush_count - last_flush_count_ >= 0x8000000U)
810 << "Received a Flush message out-of-order";
811
812 if (flush_count > last_flush_count_ &&
813 ui::LatencyInfo::Verify(latency_info,
814 "GpuCommandBufferStub::OnAsyncFlush") &&
815 !latency_info_callback_.is_null()) {
816 latency_info_callback_.Run(latency_info);
817 }
818
819 last_flush_count_ = flush_count;
820 gpu::CommandBuffer::State pre_state = command_buffer_->GetLastState();
821 command_buffer_->Flush(put_offset);
822 gpu::CommandBuffer::State post_state = command_buffer_->GetLastState();
823
824 if (pre_state.get_offset != post_state.get_offset)
825 ReportState();
826
827 #if defined(OS_ANDROID)
828 GpuChannelManager* manager = channel_->gpu_channel_manager();
829 manager->DidAccessGpu();
830 #endif
831 }
832
833 void GpuCommandBufferStub::OnRegisterTransferBuffer(
834 int32_t id,
835 base::SharedMemoryHandle transfer_buffer,
836 uint32_t size) {
837 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnRegisterTransferBuffer");
838
839 // Take ownership of the memory and map it into this process.
840 // This validates the size.
841 scoped_ptr<base::SharedMemory> shared_memory(
842 new base::SharedMemory(transfer_buffer, false));
843 if (!shared_memory->Map(size)) {
844 DVLOG(0) << "Failed to map shared memory.";
845 return;
846 }
847
848 if (command_buffer_) {
849 command_buffer_->RegisterTransferBuffer(
850 id, gpu::MakeBackingFromSharedMemory(std::move(shared_memory), size));
851 }
852 }
853
854 void GpuCommandBufferStub::OnDestroyTransferBuffer(int32_t id) {
855 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnDestroyTransferBuffer");
856
857 if (command_buffer_)
858 command_buffer_->DestroyTransferBuffer(id);
859 }
860
861 void GpuCommandBufferStub::OnCommandProcessed() {
862 if (watchdog_)
863 watchdog_->CheckArmed();
864 }
865
866 void GpuCommandBufferStub::ReportState() { command_buffer_->UpdateState(); }
867
868 void GpuCommandBufferStub::PutChanged() {
869 FastSetActiveURL(active_url_, active_url_hash_, channel_);
870 executor_->PutChanged();
871 }
872
873 void GpuCommandBufferStub::PullTextureUpdates(
874 gpu::CommandBufferNamespace namespace_id,
875 gpu::CommandBufferId command_buffer_id,
876 uint32_t release) {
877 gpu::gles2::MailboxManager* mailbox_manager =
878 context_group_->mailbox_manager();
879 if (mailbox_manager->UsesSync() && MakeCurrent()) {
880 gpu::SyncToken sync_token(namespace_id, 0, command_buffer_id, release);
881 mailbox_manager->PullTextureUpdates(sync_token);
882 }
883 }
884
885 void GpuCommandBufferStub::OnSignalSyncToken(const gpu::SyncToken& sync_token,
886 uint32_t id) {
887 scoped_refptr<gpu::SyncPointClientState> release_state =
888 sync_point_manager_->GetSyncPointClientState(
889 sync_token.namespace_id(), sync_token.command_buffer_id());
890
891 if (release_state) {
892 sync_point_client_->Wait(release_state.get(), sync_token.release_count(),
893 base::Bind(&GpuCommandBufferStub::OnSignalAck,
894 this->AsWeakPtr(), id));
895 } else {
896 OnSignalAck(id);
897 }
898 }
899
900 void GpuCommandBufferStub::OnSignalAck(uint32_t id) {
901 Send(new GpuCommandBufferMsg_SignalAck(route_id_, id));
902 }
903
904 void GpuCommandBufferStub::OnSignalQuery(uint32_t query_id, uint32_t id) {
905 if (decoder_) {
906 gpu::gles2::QueryManager* query_manager = decoder_->GetQueryManager();
907 if (query_manager) {
908 gpu::gles2::QueryManager::Query* query =
909 query_manager->GetQuery(query_id);
910 if (query) {
911 query->AddCallback(
912 base::Bind(&GpuCommandBufferStub::OnSignalAck,
913 this->AsWeakPtr(),
914 id));
915 return;
916 }
917 }
918 }
919 // Something went wrong, run callback immediately.
920 OnSignalAck(id);
921 }
922
923 void GpuCommandBufferStub::OnFenceSyncRelease(uint64_t release) {
924 if (sync_point_client_->client_state()->IsFenceSyncReleased(release)) {
925 DLOG(ERROR) << "Fence Sync has already been released.";
926 return;
927 }
928
929 gpu::gles2::MailboxManager* mailbox_manager =
930 context_group_->mailbox_manager();
931 if (mailbox_manager->UsesSync() && MakeCurrent()) {
932 gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0,
933 command_buffer_id_, release);
934 mailbox_manager->PushTextureUpdates(sync_token);
935 }
936
937 sync_point_client_->ReleaseFenceSync(release);
938 }
939
940 bool GpuCommandBufferStub::OnWaitFenceSync(
941 gpu::CommandBufferNamespace namespace_id,
942 gpu::CommandBufferId command_buffer_id,
943 uint64_t release) {
944 DCHECK(!waiting_for_sync_point_);
945 DCHECK(executor_->scheduled());
946
947 scoped_refptr<gpu::SyncPointClientState> release_state =
948 sync_point_manager_->GetSyncPointClientState(namespace_id,
949 command_buffer_id);
950
951 if (!release_state)
952 return true;
953
954 if (release_state->IsFenceSyncReleased(release)) {
955 PullTextureUpdates(namespace_id, command_buffer_id, release);
956 return true;
957 }
958
959 TRACE_EVENT_ASYNC_BEGIN1("gpu", "WaitFenceSync", this, "GpuCommandBufferStub",
960 this);
961 waiting_for_sync_point_ = true;
962 sync_point_client_->WaitNonThreadSafe(
963 release_state.get(), release, task_runner_,
964 base::Bind(&GpuCommandBufferStub::OnWaitFenceSyncCompleted,
965 this->AsWeakPtr(), namespace_id, command_buffer_id, release));
966
967 if (!waiting_for_sync_point_)
968 return true;
969
970 executor_->SetScheduled(false);
971 return false;
972 }
973
974 void GpuCommandBufferStub::OnWaitFenceSyncCompleted(
975 gpu::CommandBufferNamespace namespace_id,
976 gpu::CommandBufferId command_buffer_id,
977 uint64_t release) {
978 DCHECK(waiting_for_sync_point_);
979 TRACE_EVENT_ASYNC_END1("gpu", "WaitFenceSync", this, "GpuCommandBufferStub",
980 this);
981 PullTextureUpdates(namespace_id, command_buffer_id, release);
982 waiting_for_sync_point_ = false;
983 executor_->SetScheduled(true);
984 }
985
986 void GpuCommandBufferStub::OnCreateImage(
987 const GpuCommandBufferMsg_CreateImage_Params& params) {
988 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnCreateImage");
989 const int32_t id = params.id;
990 const gfx::GpuMemoryBufferHandle& handle = params.gpu_memory_buffer;
991 const gfx::Size& size = params.size;
992 const gfx::BufferFormat& format = params.format;
993 const uint32_t internalformat = params.internal_format;
994 const uint64_t image_release_count = params.image_release_count;
995
996 if (!decoder_)
997 return;
998
999 gpu::gles2::ImageManager* image_manager = decoder_->GetImageManager();
1000 DCHECK(image_manager);
1001 if (image_manager->LookupImage(id)) {
1002 LOG(ERROR) << "Image already exists with same ID.";
1003 return;
1004 }
1005
1006 if (!gpu::IsGpuMemoryBufferFormatSupported(format,
1007 decoder_->GetCapabilities())) {
1008 LOG(ERROR) << "Format is not supported.";
1009 return;
1010 }
1011
1012 if (!gpu::IsImageSizeValidForGpuMemoryBufferFormat(size, format)) {
1013 LOG(ERROR) << "Invalid image size for format.";
1014 return;
1015 }
1016
1017 if (!gpu::IsImageFormatCompatibleWithGpuMemoryBufferFormat(internalformat,
1018 format)) {
1019 LOG(ERROR) << "Incompatible image format.";
1020 return;
1021 }
1022
1023 scoped_refptr<gl::GLImage> image = channel()->CreateImageForGpuMemoryBuffer(
1024 handle, size, format, internalformat);
1025 if (!image.get())
1026 return;
1027
1028 image_manager->AddImage(image.get(), id);
1029 if (image_release_count) {
1030 sync_point_client_->ReleaseFenceSync(image_release_count);
1031 }
1032 }
1033
1034 void GpuCommandBufferStub::OnDestroyImage(int32_t id) {
1035 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnDestroyImage");
1036
1037 if (!decoder_)
1038 return;
1039
1040 gpu::gles2::ImageManager* image_manager = decoder_->GetImageManager();
1041 DCHECK(image_manager);
1042 if (!image_manager->LookupImage(id)) {
1043 LOG(ERROR) << "Image with ID doesn't exist.";
1044 return;
1045 }
1046
1047 image_manager->RemoveImage(id);
1048 }
1049
1050 void GpuCommandBufferStub::SendConsoleMessage(int32_t id,
1051 const std::string& message) {
1052 GPUCommandBufferConsoleMessage console_message;
1053 console_message.id = id;
1054 console_message.message = message;
1055 IPC::Message* msg = new GpuCommandBufferMsg_ConsoleMsg(
1056 route_id_, console_message);
1057 msg->set_unblock(true);
1058 Send(msg);
1059 }
1060
1061 void GpuCommandBufferStub::SendCachedShader(
1062 const std::string& key, const std::string& shader) {
1063 channel_->CacheShader(key, shader);
1064 }
1065
1066 void GpuCommandBufferStub::AddDestructionObserver(
1067 DestructionObserver* observer) {
1068 destruction_observers_.AddObserver(observer);
1069 }
1070
1071 void GpuCommandBufferStub::RemoveDestructionObserver(
1072 DestructionObserver* observer) {
1073 destruction_observers_.RemoveObserver(observer);
1074 }
1075
1076 const gpu::gles2::FeatureInfo* GpuCommandBufferStub::GetFeatureInfo() const {
1077 return context_group_->feature_info();
1078 }
1079
1080 gpu::gles2::MemoryTracker* GpuCommandBufferStub::GetMemoryTracker() const {
1081 return context_group_->memory_tracker();
1082 }
1083
1084 bool GpuCommandBufferStub::CheckContextLost() {
1085 DCHECK(command_buffer_);
1086 gpu::CommandBuffer::State state = command_buffer_->GetLastState();
1087 bool was_lost = state.error == gpu::error::kLostContext;
1088
1089 if (was_lost) {
1090 bool was_lost_by_robustness =
1091 decoder_ && decoder_->WasContextLostByRobustnessExtension();
1092
1093 // Work around issues with recovery by allowing a new GPU process to launch.
1094 if ((was_lost_by_robustness ||
1095 context_group_->feature_info()->workarounds().exit_on_context_lost) &&
1096 !channel_->gpu_channel_manager()->gpu_preferences().single_process &&
1097 !channel_->gpu_channel_manager()->gpu_preferences().in_process_gpu) {
1098 LOG(ERROR) << "Exiting GPU process because some drivers cannot recover"
1099 << " from problems.";
1100 // Signal the message loop to quit to shut down other threads
1101 // gracefully.
1102 base::MessageLoop::current()->QuitNow();
1103 }
1104
1105 // Lose all other contexts if the reset was triggered by the robustness
1106 // extension instead of being synthetic.
1107 if (was_lost_by_robustness &&
1108 (gfx::GLContext::LosesAllContextsOnContextLost() ||
1109 use_virtualized_gl_context_)) {
1110 channel_->LoseAllContexts();
1111 }
1112 }
1113
1114 CheckCompleteWaits();
1115 return was_lost;
1116 }
1117
1118 void GpuCommandBufferStub::MarkContextLost() {
1119 if (!command_buffer_ ||
1120 command_buffer_->GetLastState().error == gpu::error::kLostContext)
1121 return;
1122
1123 command_buffer_->SetContextLostReason(gpu::error::kUnknown);
1124 if (decoder_)
1125 decoder_->MarkContextLost(gpu::error::kUnknown);
1126 command_buffer_->SetParseError(gpu::error::kLostContext);
1127 }
1128
1129 void GpuCommandBufferStub::SendSwapBuffersCompleted(
1130 const std::vector<ui::LatencyInfo>& latency_info,
1131 gfx::SwapResult result) {
1132 Send(new GpuCommandBufferMsg_SwapBuffersCompleted(route_id_, latency_info,
1133 result));
1134 }
1135
1136 void GpuCommandBufferStub::SendUpdateVSyncParameters(base::TimeTicks timebase,
1137 base::TimeDelta interval) {
1138 Send(new GpuCommandBufferMsg_UpdateVSyncParameters(route_id_, timebase,
1139 interval));
1140 }
1141
1142 } // namespace content
OLDNEW
« no previous file with comments | « content/common/gpu/gpu_command_buffer_stub.h ('k') | content/common/gpu/gpu_config.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698