1 // Copyright 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 "gpu/command_buffer/service/in_process_command_buffer.h"
6
7 #include <queue>
8 #include <set>
9 #include <utility>
10
11 #include <GLES2/gl2.h>
12 #ifndef GL_GLEXT_PROTOTYPES
13 #define GL_GLEXT_PROTOTYPES 1
14 #endif
15 #include <GLES2/gl2ext.h>
16 #include <GLES2/gl2extchromium.h>
17
18 #include "base/bind.h"
19 #include "base/bind_helpers.h"
20 #include "base/lazy_instance.h"
21 #include "base/logging.h"
22 #include "base/memory/weak_ptr.h"
23 #include "base/message_loop/message_loop_proxy.h"
24 #include "base/sequence_checker.h"
25 #include "base/synchronization/condition_variable.h"
26 #include "base/threading/thread.h"
27 #include "gpu/command_buffer/service/command_buffer_service.h"
28 #include "gpu/command_buffer/service/context_group.h"
29 #include "gpu/command_buffer/service/gl_context_virtual.h"
30 #include "gpu/command_buffer/service/gpu_scheduler.h"
31 #include "gpu/command_buffer/service/image_manager.h"
32 #include "gpu/command_buffer/service/mailbox_manager.h"
33 #include "gpu/command_buffer/service/memory_tracking.h"
34 #include "gpu/command_buffer/service/query_manager.h"
35 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
36 #include "ui/gfx/size.h"
37 #include "ui/gl/gl_context.h"
38 #include "ui/gl/gl_image.h"
39 #include "ui/gl/gl_share_group.h"
40
41 #if defined(OS_ANDROID)
42 #include "gpu/command_buffer/service/stream_texture_manager_in_process_android.h"
43 #include "ui/gl/android/surface_texture.h"
44 #endif
45
46 namespace gpu {
47
48 namespace {
49
50 static InProcessGpuMemoryBufferFactory* g_gpu_memory_buffer_factory = NULL;
51
52 template <typename T>
RunTaskWithResult(base::Callback<T (void)> task,T * result,base::WaitableEvent * completion)53 static void RunTaskWithResult(base::Callback<T(void)> task,
54 T* result,
55 base::WaitableEvent* completion) {
56 *result = task.Run();
57 completion->Signal();
58 }
59
60 class GpuInProcessThread
61 : public base::Thread,
62 public InProcessCommandBuffer::Service,
63 public base::RefCountedThreadSafe<GpuInProcessThread> {
64 public:
65 GpuInProcessThread();
66
AddRef() const67 virtual void AddRef() const OVERRIDE {
68 base::RefCountedThreadSafe<GpuInProcessThread>::AddRef();
69 }
Release() const70 virtual void Release() const OVERRIDE {
71 base::RefCountedThreadSafe<GpuInProcessThread>::Release();
72 }
73
74 virtual void ScheduleTask(const base::Closure& task) OVERRIDE;
75 virtual void ScheduleIdleWork(const base::Closure& callback) OVERRIDE;
UseVirtualizedGLContexts()76 virtual bool UseVirtualizedGLContexts() OVERRIDE { return false; }
77 virtual scoped_refptr<gles2::ShaderTranslatorCache> shader_translator_cache()
78 OVERRIDE;
79
80 private:
81 virtual ~GpuInProcessThread();
82 friend class base::RefCountedThreadSafe<GpuInProcessThread>;
83
84 scoped_refptr<gpu::gles2::ShaderTranslatorCache> shader_translator_cache_;
85 DISALLOW_COPY_AND_ASSIGN(GpuInProcessThread);
86 };
87
GpuInProcessThread()88 GpuInProcessThread::GpuInProcessThread() : base::Thread("GpuThread") {
89 Start();
90 }
91
~GpuInProcessThread()92 GpuInProcessThread::~GpuInProcessThread() {
93 Stop();
94 }
95
ScheduleTask(const base::Closure & task)96 void GpuInProcessThread::ScheduleTask(const base::Closure& task) {
97 message_loop()->PostTask(FROM_HERE, task);
98 }
99
ScheduleIdleWork(const base::Closure & callback)100 void GpuInProcessThread::ScheduleIdleWork(const base::Closure& callback) {
101 message_loop()->PostDelayedTask(
102 FROM_HERE, callback, base::TimeDelta::FromMilliseconds(5));
103 }
104
105 scoped_refptr<gles2::ShaderTranslatorCache>
shader_translator_cache()106 GpuInProcessThread::shader_translator_cache() {
107 if (!shader_translator_cache_.get())
108 shader_translator_cache_ = new gpu::gles2::ShaderTranslatorCache;
109 return shader_translator_cache_;
110 }
111
112 base::LazyInstance<std::set<InProcessCommandBuffer*> > default_thread_clients_ =
113 LAZY_INSTANCE_INITIALIZER;
114 base::LazyInstance<base::Lock> default_thread_clients_lock_ =
115 LAZY_INSTANCE_INITIALIZER;
116
117 class ScopedEvent {
118 public:
ScopedEvent(base::WaitableEvent * event)119 ScopedEvent(base::WaitableEvent* event) : event_(event) {}
~ScopedEvent()120 ~ScopedEvent() { event_->Signal(); }
121
122 private:
123 base::WaitableEvent* event_;
124 };
125
126 class SyncPointManager {
127 public:
128 SyncPointManager();
129 ~SyncPointManager();
130
131 uint32 GenerateSyncPoint();
132 void RetireSyncPoint(uint32 sync_point);
133
134 bool IsSyncPointPassed(uint32 sync_point);
135 void WaitSyncPoint(uint32 sync_point);
136
137 private:
138 // This lock protects access to pending_sync_points_ and next_sync_point_ and
139 // is used with the ConditionVariable to signal when a sync point is retired.
140 base::Lock lock_;
141 std::set<uint32> pending_sync_points_;
142 uint32 next_sync_point_;
143 base::ConditionVariable cond_var_;
144 };
145
SyncPointManager()146 SyncPointManager::SyncPointManager() : next_sync_point_(1), cond_var_(&lock_) {}
147
~SyncPointManager()148 SyncPointManager::~SyncPointManager() {
149 DCHECK_EQ(pending_sync_points_.size(), 0U);
150 }
151
GenerateSyncPoint()152 uint32 SyncPointManager::GenerateSyncPoint() {
153 base::AutoLock lock(lock_);
154 uint32 sync_point = next_sync_point_++;
155 DCHECK_EQ(pending_sync_points_.count(sync_point), 0U);
156 pending_sync_points_.insert(sync_point);
157 return sync_point;
158 }
159
RetireSyncPoint(uint32 sync_point)160 void SyncPointManager::RetireSyncPoint(uint32 sync_point) {
161 base::AutoLock lock(lock_);
162 DCHECK(pending_sync_points_.count(sync_point));
163 pending_sync_points_.erase(sync_point);
164 cond_var_.Broadcast();
165 }
166
IsSyncPointPassed(uint32 sync_point)167 bool SyncPointManager::IsSyncPointPassed(uint32 sync_point) {
168 base::AutoLock lock(lock_);
169 return pending_sync_points_.count(sync_point) == 0;
170 }
171
WaitSyncPoint(uint32 sync_point)172 void SyncPointManager::WaitSyncPoint(uint32 sync_point) {
173 base::AutoLock lock(lock_);
174 while (pending_sync_points_.count(sync_point)) {
175 cond_var_.Wait();
176 }
177 }
178
179 base::LazyInstance<SyncPointManager> g_sync_point_manager =
180 LAZY_INSTANCE_INITIALIZER;
181
182 } // anonyous namespace
183
Service()184 InProcessCommandBuffer::Service::Service() {}
185
~Service()186 InProcessCommandBuffer::Service::~Service() {}
187
188 scoped_refptr<gles2::MailboxManager>
mailbox_manager()189 InProcessCommandBuffer::Service::mailbox_manager() {
190 if (!mailbox_manager_.get())
191 mailbox_manager_ = new gles2::MailboxManager();
192 return mailbox_manager_;
193 }
194
195 scoped_refptr<InProcessCommandBuffer::Service>
GetDefaultService()196 InProcessCommandBuffer::GetDefaultService() {
197 base::AutoLock lock(default_thread_clients_lock_.Get());
198 scoped_refptr<Service> service;
199 if (!default_thread_clients_.Get().empty()) {
200 InProcessCommandBuffer* other = *default_thread_clients_.Get().begin();
201 service = other->service_;
202 DCHECK(service.get());
203 } else {
204 service = new GpuInProcessThread;
205 }
206 return service;
207 }
208
InProcessCommandBuffer(const scoped_refptr<Service> & service)209 InProcessCommandBuffer::InProcessCommandBuffer(
210 const scoped_refptr<Service>& service)
211 : context_lost_(false),
212 idle_work_pending_(false),
213 last_put_offset_(-1),
214 flush_event_(false, false),
215 service_(service.get() ? service : GetDefaultService()),
216 gpu_thread_weak_ptr_factory_(this) {
217 if (!service.get()) {
218 base::AutoLock lock(default_thread_clients_lock_.Get());
219 default_thread_clients_.Get().insert(this);
220 }
221 }
222
~InProcessCommandBuffer()223 InProcessCommandBuffer::~InProcessCommandBuffer() {
224 Destroy();
225 base::AutoLock lock(default_thread_clients_lock_.Get());
226 default_thread_clients_.Get().erase(this);
227 }
228
OnResizeView(gfx::Size size,float scale_factor)229 void InProcessCommandBuffer::OnResizeView(gfx::Size size, float scale_factor) {
230 CheckSequencedThread();
231 DCHECK(!surface_->IsOffscreen());
232 surface_->Resize(size);
233 }
234
MakeCurrent()235 bool InProcessCommandBuffer::MakeCurrent() {
236 CheckSequencedThread();
237 command_buffer_lock_.AssertAcquired();
238
239 if (!context_lost_ && decoder_->MakeCurrent())
240 return true;
241 DLOG(ERROR) << "Context lost because MakeCurrent failed.";
242 command_buffer_->SetContextLostReason(decoder_->GetContextLostReason());
243 command_buffer_->SetParseError(gpu::error::kLostContext);
244 return false;
245 }
246
PumpCommands()247 void InProcessCommandBuffer::PumpCommands() {
248 CheckSequencedThread();
249 command_buffer_lock_.AssertAcquired();
250
251 if (!MakeCurrent())
252 return;
253
254 gpu_scheduler_->PutChanged();
255 }
256
GetBufferChanged(int32 transfer_buffer_id)257 bool InProcessCommandBuffer::GetBufferChanged(int32 transfer_buffer_id) {
258 CheckSequencedThread();
259 command_buffer_lock_.AssertAcquired();
260 command_buffer_->SetGetBuffer(transfer_buffer_id);
261 return true;
262 }
263
Initialize(scoped_refptr<gfx::GLSurface> surface,bool is_offscreen,gfx::AcceleratedWidget window,const gfx::Size & size,const std::vector<int32> & attribs,gfx::GpuPreference gpu_preference,const base::Closure & context_lost_callback,InProcessCommandBuffer * share_group)264 bool InProcessCommandBuffer::Initialize(
265 scoped_refptr<gfx::GLSurface> surface,
266 bool is_offscreen,
267 gfx::AcceleratedWidget window,
268 const gfx::Size& size,
269 const std::vector<int32>& attribs,
270 gfx::GpuPreference gpu_preference,
271 const base::Closure& context_lost_callback,
272 InProcessCommandBuffer* share_group) {
273 DCHECK(!share_group || service_.get() == share_group->service_.get());
274 context_lost_callback_ = WrapCallback(context_lost_callback);
275
276 if (surface.get()) {
277 // GPU thread must be the same as client thread due to GLSurface not being
278 // thread safe.
279 sequence_checker_.reset(new base::SequenceChecker);
280 surface_ = surface;
281 }
282
283 gpu::Capabilities capabilities;
284 InitializeOnGpuThreadParams params(is_offscreen,
285 window,
286 size,
287 attribs,
288 gpu_preference,
289 &capabilities,
290 share_group);
291
292 base::Callback<bool(void)> init_task =
293 base::Bind(&InProcessCommandBuffer::InitializeOnGpuThread,
294 base::Unretained(this),
295 params);
296
297 base::WaitableEvent completion(true, false);
298 bool result = false;
299 QueueTask(
300 base::Bind(&RunTaskWithResult<bool>, init_task, &result, &completion));
301 completion.Wait();
302
303 if (result) {
304 capabilities_ = capabilities;
305 capabilities_.map_image =
306 capabilities_.map_image && g_gpu_memory_buffer_factory;
307 }
308 return result;
309 }
310
InitializeOnGpuThread(const InitializeOnGpuThreadParams & params)311 bool InProcessCommandBuffer::InitializeOnGpuThread(
312 const InitializeOnGpuThreadParams& params) {
313 CheckSequencedThread();
314 gpu_thread_weak_ptr_ = gpu_thread_weak_ptr_factory_.GetWeakPtr();
315
316 DCHECK(params.size.width() >= 0 && params.size.height() >= 0);
317
318 TransferBufferManager* manager = new TransferBufferManager();
319 transfer_buffer_manager_.reset(manager);
320 manager->Initialize();
321
322 scoped_ptr<CommandBufferService> command_buffer(
323 new CommandBufferService(transfer_buffer_manager_.get()));
324 command_buffer->SetPutOffsetChangeCallback(base::Bind(
325 &InProcessCommandBuffer::PumpCommands, gpu_thread_weak_ptr_));
326 command_buffer->SetParseErrorCallback(base::Bind(
327 &InProcessCommandBuffer::OnContextLost, gpu_thread_weak_ptr_));
328
329 if (!command_buffer->Initialize()) {
330 LOG(ERROR) << "Could not initialize command buffer.";
331 DestroyOnGpuThread();
332 return false;
333 }
334
335 gl_share_group_ = params.context_group
336 ? params.context_group->gl_share_group_.get()
337 : new gfx::GLShareGroup;
338
339 #if defined(OS_ANDROID)
340 stream_texture_manager_.reset(new StreamTextureManagerInProcess);
341 #endif
342
343 bool bind_generates_resource = false;
344 decoder_.reset(gles2::GLES2Decoder::Create(
345 params.context_group
346 ? params.context_group->decoder_->GetContextGroup()
347 : new gles2::ContextGroup(service_->mailbox_manager(),
348 NULL,
349 service_->shader_translator_cache(),
350 NULL,
351 bind_generates_resource)));
352
353 gpu_scheduler_.reset(
354 new GpuScheduler(command_buffer.get(), decoder_.get(), decoder_.get()));
355 command_buffer->SetGetBufferChangeCallback(base::Bind(
356 &GpuScheduler::SetGetBuffer, base::Unretained(gpu_scheduler_.get())));
357 command_buffer_ = command_buffer.Pass();
358
359 decoder_->set_engine(gpu_scheduler_.get());
360
361 if (!surface_.get()) {
362 if (params.is_offscreen)
363 surface_ = gfx::GLSurface::CreateOffscreenGLSurface(params.size);
364 else
365 surface_ = gfx::GLSurface::CreateViewGLSurface(params.window);
366 }
367
368 if (!surface_.get()) {
369 LOG(ERROR) << "Could not create GLSurface.";
370 DestroyOnGpuThread();
371 return false;
372 }
373
374 if (service_->UseVirtualizedGLContexts() ||
375 decoder_->GetContextGroup()
376 ->feature_info()
377 ->workarounds()
378 .use_virtualized_gl_contexts) {
379 context_ = gl_share_group_->GetSharedContext();
380 if (!context_.get()) {
381 context_ = gfx::GLContext::CreateGLContext(
382 gl_share_group_.get(), surface_.get(), params.gpu_preference);
383 gl_share_group_->SetSharedContext(context_.get());
384 }
385
386 context_ = new GLContextVirtual(
387 gl_share_group_.get(), context_.get(), decoder_->AsWeakPtr());
388 if (context_->Initialize(surface_.get(), params.gpu_preference)) {
389 VLOG(1) << "Created virtual GL context.";
390 } else {
391 context_ = NULL;
392 }
393 } else {
394 context_ = gfx::GLContext::CreateGLContext(
395 gl_share_group_.get(), surface_.get(), params.gpu_preference);
396 }
397
398 if (!context_.get()) {
399 LOG(ERROR) << "Could not create GLContext.";
400 DestroyOnGpuThread();
401 return false;
402 }
403
404 if (!context_->MakeCurrent(surface_.get())) {
405 LOG(ERROR) << "Could not make context current.";
406 DestroyOnGpuThread();
407 return false;
408 }
409
410 gles2::DisallowedFeatures disallowed_features;
411 disallowed_features.gpu_memory_manager = true;
412 if (!decoder_->Initialize(surface_,
413 context_,
414 params.is_offscreen,
415 params.size,
416 disallowed_features,
417 params.attribs)) {
418 LOG(ERROR) << "Could not initialize decoder.";
419 DestroyOnGpuThread();
420 return false;
421 }
422 *params.capabilities = decoder_->GetCapabilities();
423
424 if (!params.is_offscreen) {
425 decoder_->SetResizeCallback(base::Bind(
426 &InProcessCommandBuffer::OnResizeView, gpu_thread_weak_ptr_));
427 }
428 decoder_->SetWaitSyncPointCallback(
429 base::Bind(&InProcessCommandBuffer::WaitSyncPointOnGpuThread,
430 base::Unretained(this)));
431
432 return true;
433 }
434
Destroy()435 void InProcessCommandBuffer::Destroy() {
436 CheckSequencedThread();
437
438 base::WaitableEvent completion(true, false);
439 bool result = false;
440 base::Callback<bool(void)> destroy_task = base::Bind(
441 &InProcessCommandBuffer::DestroyOnGpuThread, base::Unretained(this));
442 QueueTask(
443 base::Bind(&RunTaskWithResult<bool>, destroy_task, &result, &completion));
444 completion.Wait();
445 }
446
DestroyOnGpuThread()447 bool InProcessCommandBuffer::DestroyOnGpuThread() {
448 CheckSequencedThread();
449 gpu_thread_weak_ptr_factory_.InvalidateWeakPtrs();
450 command_buffer_.reset();
451 // Clean up GL resources if possible.
452 bool have_context = context_.get() && context_->MakeCurrent(surface_.get());
453 if (decoder_) {
454 decoder_->Destroy(have_context);
455 decoder_.reset();
456 }
457 context_ = NULL;
458 surface_ = NULL;
459 gl_share_group_ = NULL;
460 #if defined(OS_ANDROID)
461 stream_texture_manager_.reset();
462 #endif
463
464 return true;
465 }
466
CheckSequencedThread()467 void InProcessCommandBuffer::CheckSequencedThread() {
468 DCHECK(!sequence_checker_ ||
469 sequence_checker_->CalledOnValidSequencedThread());
470 }
471
OnContextLost()472 void InProcessCommandBuffer::OnContextLost() {
473 CheckSequencedThread();
474 if (!context_lost_callback_.is_null()) {
475 context_lost_callback_.Run();
476 context_lost_callback_.Reset();
477 }
478
479 context_lost_ = true;
480 }
481
GetStateFast()482 CommandBuffer::State InProcessCommandBuffer::GetStateFast() {
483 CheckSequencedThread();
484 base::AutoLock lock(state_after_last_flush_lock_);
485 if (state_after_last_flush_.generation - last_state_.generation < 0x80000000U)
486 last_state_ = state_after_last_flush_;
487 return last_state_;
488 }
489
GetLastState()490 CommandBuffer::State InProcessCommandBuffer::GetLastState() {
491 CheckSequencedThread();
492 return last_state_;
493 }
494
GetLastToken()495 int32 InProcessCommandBuffer::GetLastToken() {
496 CheckSequencedThread();
497 GetStateFast();
498 return last_state_.token;
499 }
500
FlushOnGpuThread(int32 put_offset)501 void InProcessCommandBuffer::FlushOnGpuThread(int32 put_offset) {
502 CheckSequencedThread();
503 ScopedEvent handle_flush(&flush_event_);
504 base::AutoLock lock(command_buffer_lock_);
505 command_buffer_->Flush(put_offset);
506 {
507 // Update state before signaling the flush event.
508 base::AutoLock lock(state_after_last_flush_lock_);
509 state_after_last_flush_ = command_buffer_->GetLastState();
510 }
511 DCHECK((!error::IsError(state_after_last_flush_.error) && !context_lost_) ||
512 (error::IsError(state_after_last_flush_.error) && context_lost_));
513
514 // If we've processed all pending commands but still have pending queries,
515 // pump idle work until the query is passed.
516 if (put_offset == state_after_last_flush_.get_offset &&
517 gpu_scheduler_->HasMoreWork()) {
518 ScheduleIdleWorkOnGpuThread();
519 }
520 }
521
PerformIdleWork()522 void InProcessCommandBuffer::PerformIdleWork() {
523 CheckSequencedThread();
524 idle_work_pending_ = false;
525 base::AutoLock lock(command_buffer_lock_);
526 if (MakeCurrent() && gpu_scheduler_->HasMoreWork()) {
527 gpu_scheduler_->PerformIdleWork();
528 ScheduleIdleWorkOnGpuThread();
529 }
530 }
531
ScheduleIdleWorkOnGpuThread()532 void InProcessCommandBuffer::ScheduleIdleWorkOnGpuThread() {
533 CheckSequencedThread();
534 if (idle_work_pending_)
535 return;
536 idle_work_pending_ = true;
537 service_->ScheduleIdleWork(
538 base::Bind(&InProcessCommandBuffer::PerformIdleWork,
539 gpu_thread_weak_ptr_));
540 }
541
Flush(int32 put_offset)542 void InProcessCommandBuffer::Flush(int32 put_offset) {
543 CheckSequencedThread();
544 if (last_state_.error != gpu::error::kNoError)
545 return;
546
547 if (last_put_offset_ == put_offset)
548 return;
549
550 last_put_offset_ = put_offset;
551 base::Closure task = base::Bind(&InProcessCommandBuffer::FlushOnGpuThread,
552 gpu_thread_weak_ptr_,
553 put_offset);
554 QueueTask(task);
555 }
556
WaitForTokenInRange(int32 start,int32 end)557 void InProcessCommandBuffer::WaitForTokenInRange(int32 start, int32 end) {
558 CheckSequencedThread();
559 while (!InRange(start, end, GetLastToken()) &&
560 last_state_.error == gpu::error::kNoError)
561 flush_event_.Wait();
562 }
563
WaitForGetOffsetInRange(int32 start,int32 end)564 void InProcessCommandBuffer::WaitForGetOffsetInRange(int32 start, int32 end) {
565 CheckSequencedThread();
566
567 GetStateFast();
568 while (!InRange(start, end, last_state_.get_offset) &&
569 last_state_.error == gpu::error::kNoError) {
570 flush_event_.Wait();
571 GetStateFast();
572 }
573 }
574
SetGetBuffer(int32 shm_id)575 void InProcessCommandBuffer::SetGetBuffer(int32 shm_id) {
576 CheckSequencedThread();
577 if (last_state_.error != gpu::error::kNoError)
578 return;
579
580 {
581 base::AutoLock lock(command_buffer_lock_);
582 command_buffer_->SetGetBuffer(shm_id);
583 last_put_offset_ = 0;
584 }
585 {
586 base::AutoLock lock(state_after_last_flush_lock_);
587 state_after_last_flush_ = command_buffer_->GetLastState();
588 }
589 }
590
CreateTransferBuffer(size_t size,int32 * id)591 scoped_refptr<Buffer> InProcessCommandBuffer::CreateTransferBuffer(size_t size,
592 int32* id) {
593 CheckSequencedThread();
594 base::AutoLock lock(command_buffer_lock_);
595 return command_buffer_->CreateTransferBuffer(size, id);
596 }
597
DestroyTransferBuffer(int32 id)598 void InProcessCommandBuffer::DestroyTransferBuffer(int32 id) {
599 CheckSequencedThread();
600 base::Closure task =
601 base::Bind(&InProcessCommandBuffer::DestroyTransferBufferOnGpuThread,
602 base::Unretained(this),
603 id);
604
605 QueueTask(task);
606 }
607
DestroyTransferBufferOnGpuThread(int32 id)608 void InProcessCommandBuffer::DestroyTransferBufferOnGpuThread(int32 id) {
609 base::AutoLock lock(command_buffer_lock_);
610 command_buffer_->DestroyTransferBuffer(id);
611 }
612
GetCapabilities()613 gpu::Capabilities InProcessCommandBuffer::GetCapabilities() {
614 return capabilities_;
615 }
616
CreateGpuMemoryBuffer(size_t width,size_t height,unsigned internalformat,unsigned usage,int32 * id)617 gfx::GpuMemoryBuffer* InProcessCommandBuffer::CreateGpuMemoryBuffer(
618 size_t width,
619 size_t height,
620 unsigned internalformat,
621 unsigned usage,
622 int32* id) {
623 CheckSequencedThread();
624
625 *id = -1;
626
627 scoped_ptr<gfx::GpuMemoryBuffer> buffer =
628 g_gpu_memory_buffer_factory->AllocateGpuMemoryBuffer(
629 width, height, internalformat, usage);
630 if (!buffer.get())
631 return NULL;
632
633 static int32 next_id = 1;
634 int32 new_id = next_id++;
635
636 base::Closure task =
637 base::Bind(&InProcessCommandBuffer::RegisterGpuMemoryBufferOnGpuThread,
638 base::Unretained(this),
639 new_id,
640 buffer->GetHandle(),
641 width,
642 height,
643 internalformat);
644
645 QueueTask(task);
646
647 *id = new_id;
648 DCHECK(gpu_memory_buffers_.find(new_id) == gpu_memory_buffers_.end());
649 return gpu_memory_buffers_.add(new_id, buffer.Pass()).first->second;
650 }
651
RegisterGpuMemoryBufferOnGpuThread(int32 id,const gfx::GpuMemoryBufferHandle & handle,size_t width,size_t height,unsigned internalformat)652 void InProcessCommandBuffer::RegisterGpuMemoryBufferOnGpuThread(
653 int32 id,
654 const gfx::GpuMemoryBufferHandle& handle,
655 size_t width,
656 size_t height,
657 unsigned internalformat) {
658 scoped_refptr<gfx::GLImage> image =
659 g_gpu_memory_buffer_factory->CreateImageForGpuMemoryBuffer(
660 handle, gfx::Size(width, height), internalformat);
661 if (!image.get())
662 return;
663
664 // For Android specific workaround.
665 gles2::ContextGroup* context_group = decoder_->GetContextGroup();
666 if (context_group->feature_info()->workarounds().release_image_after_use)
667 image->SetReleaseAfterUse();
668
669 if (decoder_) {
670 gpu::gles2::ImageManager* image_manager = decoder_->GetImageManager();
671 DCHECK(image_manager);
672 image_manager->AddImage(image.get(), id);
673 }
674 }
675
DestroyGpuMemoryBuffer(int32 id)676 void InProcessCommandBuffer::DestroyGpuMemoryBuffer(int32 id) {
677 CheckSequencedThread();
678
679 base::Closure task =
680 base::Bind(&InProcessCommandBuffer::UnregisterGpuMemoryBufferOnGpuThread,
681 base::Unretained(this),
682 id);
683
684 QueueTask(task);
685
686 gpu_memory_buffers_.erase(id);
687 }
688
UnregisterGpuMemoryBufferOnGpuThread(int32 id)689 void InProcessCommandBuffer::UnregisterGpuMemoryBufferOnGpuThread(int32 id) {
690 if (decoder_) {
691 gpu::gles2::ImageManager* image_manager = decoder_->GetImageManager();
692 DCHECK(image_manager);
693 image_manager->RemoveImage(id);
694 }
695 }
696
InsertSyncPoint()697 uint32 InProcessCommandBuffer::InsertSyncPoint() {
698 uint32 sync_point = g_sync_point_manager.Get().GenerateSyncPoint();
699 QueueTask(base::Bind(&InProcessCommandBuffer::RetireSyncPointOnGpuThread,
700 base::Unretained(this),
701 sync_point));
702 return sync_point;
703 }
704
InsertFutureSyncPoint()705 uint32 InProcessCommandBuffer::InsertFutureSyncPoint() {
706 return g_sync_point_manager.Get().GenerateSyncPoint();
707 }
708
RetireSyncPoint(uint32 sync_point)709 void InProcessCommandBuffer::RetireSyncPoint(uint32 sync_point) {
710 QueueTask(base::Bind(&InProcessCommandBuffer::RetireSyncPointOnGpuThread,
711 base::Unretained(this),
712 sync_point));
713 }
714
RetireSyncPointOnGpuThread(uint32 sync_point)715 void InProcessCommandBuffer::RetireSyncPointOnGpuThread(uint32 sync_point) {
716 gles2::MailboxManager* mailbox_manager =
717 decoder_->GetContextGroup()->mailbox_manager();
718 if (mailbox_manager->UsesSync()) {
719 bool make_current_success = false;
720 {
721 base::AutoLock lock(command_buffer_lock_);
722 make_current_success = MakeCurrent();
723 }
724 if (make_current_success)
725 mailbox_manager->PushTextureUpdates(sync_point);
726 }
727 g_sync_point_manager.Get().RetireSyncPoint(sync_point);
728 }
729
SignalSyncPoint(unsigned sync_point,const base::Closure & callback)730 void InProcessCommandBuffer::SignalSyncPoint(unsigned sync_point,
731 const base::Closure& callback) {
732 CheckSequencedThread();
733 QueueTask(base::Bind(&InProcessCommandBuffer::SignalSyncPointOnGpuThread,
734 base::Unretained(this),
735 sync_point,
736 WrapCallback(callback)));
737 }
738
WaitSyncPointOnGpuThread(unsigned sync_point)739 bool InProcessCommandBuffer::WaitSyncPointOnGpuThread(unsigned sync_point) {
740 g_sync_point_manager.Get().WaitSyncPoint(sync_point);
741 gles2::MailboxManager* mailbox_manager =
742 decoder_->GetContextGroup()->mailbox_manager();
743 mailbox_manager->PullTextureUpdates(sync_point);
744 return true;
745 }
746
SignalSyncPointOnGpuThread(unsigned sync_point,const base::Closure & callback)747 void InProcessCommandBuffer::SignalSyncPointOnGpuThread(
748 unsigned sync_point,
749 const base::Closure& callback) {
750 if (g_sync_point_manager.Get().IsSyncPointPassed(sync_point)) {
751 callback.Run();
752 } else {
753 service_->ScheduleIdleWork(
754 base::Bind(&InProcessCommandBuffer::SignalSyncPointOnGpuThread,
755 gpu_thread_weak_ptr_,
756 sync_point,
757 callback));
758 }
759 }
760
SignalQuery(unsigned query_id,const base::Closure & callback)761 void InProcessCommandBuffer::SignalQuery(unsigned query_id,
762 const base::Closure& callback) {
763 CheckSequencedThread();
764 QueueTask(base::Bind(&InProcessCommandBuffer::SignalQueryOnGpuThread,
765 base::Unretained(this),
766 query_id,
767 WrapCallback(callback)));
768 }
769
SignalQueryOnGpuThread(unsigned query_id,const base::Closure & callback)770 void InProcessCommandBuffer::SignalQueryOnGpuThread(
771 unsigned query_id,
772 const base::Closure& callback) {
773 gles2::QueryManager* query_manager_ = decoder_->GetQueryManager();
774 DCHECK(query_manager_);
775
776 gles2::QueryManager::Query* query = query_manager_->GetQuery(query_id);
777 if (!query)
778 callback.Run();
779 else
780 query->AddCallback(callback);
781 }
782
SetSurfaceVisible(bool visible)783 void InProcessCommandBuffer::SetSurfaceVisible(bool visible) {}
784
Echo(const base::Closure & callback)785 void InProcessCommandBuffer::Echo(const base::Closure& callback) {
786 QueueTask(WrapCallback(callback));
787 }
788
CreateStreamTexture(uint32 texture_id)789 uint32 InProcessCommandBuffer::CreateStreamTexture(uint32 texture_id) {
790 base::WaitableEvent completion(true, false);
791 uint32 stream_id = 0;
792 base::Callback<uint32(void)> task =
793 base::Bind(&InProcessCommandBuffer::CreateStreamTextureOnGpuThread,
794 base::Unretained(this),
795 texture_id);
796 QueueTask(
797 base::Bind(&RunTaskWithResult<uint32>, task, &stream_id, &completion));
798 completion.Wait();
799 return stream_id;
800 }
801
CreateStreamTextureOnGpuThread(uint32 client_texture_id)802 uint32 InProcessCommandBuffer::CreateStreamTextureOnGpuThread(
803 uint32 client_texture_id) {
804 #if defined(OS_ANDROID)
805 return stream_texture_manager_->CreateStreamTexture(
806 client_texture_id, decoder_->GetContextGroup()->texture_manager());
807 #else
808 return 0;
809 #endif
810 }
811
GetLastError()812 gpu::error::Error InProcessCommandBuffer::GetLastError() {
813 CheckSequencedThread();
814 return last_state_.error;
815 }
816
Initialize()817 bool InProcessCommandBuffer::Initialize() {
818 NOTREACHED();
819 return false;
820 }
821
822 namespace {
823
PostCallback(const scoped_refptr<base::MessageLoopProxy> & loop,const base::Closure & callback)824 void PostCallback(const scoped_refptr<base::MessageLoopProxy>& loop,
825 const base::Closure& callback) {
826 if (!loop->BelongsToCurrentThread()) {
827 loop->PostTask(FROM_HERE, callback);
828 } else {
829 callback.Run();
830 }
831 }
832
RunOnTargetThread(scoped_ptr<base::Closure> callback)833 void RunOnTargetThread(scoped_ptr<base::Closure> callback) {
834 DCHECK(callback.get());
835 callback->Run();
836 }
837
838 } // anonymous namespace
839
WrapCallback(const base::Closure & callback)840 base::Closure InProcessCommandBuffer::WrapCallback(
841 const base::Closure& callback) {
842 // Make sure the callback gets deleted on the target thread by passing
843 // ownership.
844 scoped_ptr<base::Closure> scoped_callback(new base::Closure(callback));
845 base::Closure callback_on_client_thread =
846 base::Bind(&RunOnTargetThread, base::Passed(&scoped_callback));
847 base::Closure wrapped_callback =
848 base::Bind(&PostCallback, base::MessageLoopProxy::current(),
849 callback_on_client_thread);
850 return wrapped_callback;
851 }
852
853 #if defined(OS_ANDROID)
854 scoped_refptr<gfx::SurfaceTexture>
GetSurfaceTexture(uint32 stream_id)855 InProcessCommandBuffer::GetSurfaceTexture(uint32 stream_id) {
856 DCHECK(stream_texture_manager_);
857 return stream_texture_manager_->GetSurfaceTexture(stream_id);
858 }
859 #endif
860
861 // static
SetGpuMemoryBufferFactory(InProcessGpuMemoryBufferFactory * factory)862 void InProcessCommandBuffer::SetGpuMemoryBufferFactory(
863 InProcessGpuMemoryBufferFactory* factory) {
864 g_gpu_memory_buffer_factory = factory;
865 }
866
867 } // namespace gpu
868