Revert "Reland c91b178b07b0d - Delete dead signin code (SigninGlobalError)"
[chromium-blink-merge.git] / gpu / command_buffer / service / async_pixel_transfer_manager_share_group.cc
blob86eb71803cf078b1b662c45f46a00f221ab74a68
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.
5 #include "gpu/command_buffer/service/async_pixel_transfer_manager_share_group.h"
7 #include <list>
9 #include "base/bind.h"
10 #include "base/lazy_instance.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/synchronization/cancellation_flag.h"
17 #include "base/synchronization/lock.h"
18 #include "base/synchronization/waitable_event.h"
19 #include "base/threading/thread.h"
20 #include "base/threading/thread_checker.h"
21 #include "base/trace_event/trace_event.h"
22 #include "base/trace_event/trace_event_synthetic_delay.h"
23 #include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
24 #include "ui/gl/gl_bindings.h"
25 #include "ui/gl/gl_context.h"
26 #include "ui/gl/gl_surface.h"
27 #include "ui/gl/gpu_preference.h"
28 #include "ui/gl/scoped_binders.h"
30 namespace gpu {
32 namespace {
34 const char kAsyncTransferThreadName[] = "AsyncTransferThread";
36 void PerformNotifyCompletion(
37 AsyncMemoryParams mem_params,
38 scoped_refptr<AsyncPixelTransferCompletionObserver> observer) {
39 TRACE_EVENT0("gpu", "PerformNotifyCompletion");
40 observer->DidComplete(mem_params);
43 // TODO(backer): Factor out common thread scheduling logic from the EGL and
44 // ShareGroup implementations. http://crbug.com/239889
45 class TransferThread : public base::Thread {
46 public:
47 TransferThread()
48 : base::Thread(kAsyncTransferThreadName),
49 initialized_(false) {
50 base::Thread::Options options;
51 #if defined(OS_ANDROID) || defined(OS_LINUX)
52 options.priority = base::ThreadPriority::BACKGROUND;
53 #endif
54 StartWithOptions(options);
57 ~TransferThread() override {
58 // The only instance of this class was declared leaky.
59 NOTREACHED();
62 void InitializeOnMainThread(gfx::GLContext* parent_context) {
63 TRACE_EVENT0("gpu", "TransferThread::InitializeOnMainThread");
64 if (initialized_)
65 return;
67 base::WaitableEvent wait_for_init(true, false);
68 task_runner()->PostTask(
69 FROM_HERE,
70 base::Bind(&TransferThread::InitializeOnTransferThread,
71 base::Unretained(this), base::Unretained(parent_context),
72 &wait_for_init));
73 wait_for_init.Wait();
76 void CleanUp() override {
77 surface_ = NULL;
78 context_ = NULL;
81 private:
82 bool initialized_;
84 scoped_refptr<gfx::GLSurface> surface_;
85 scoped_refptr<gfx::GLContext> context_;
87 void InitializeOnTransferThread(gfx::GLContext* parent_context,
88 base::WaitableEvent* caller_wait) {
89 TRACE_EVENT0("gpu", "InitializeOnTransferThread");
91 if (!parent_context) {
92 LOG(ERROR) << "No parent context provided.";
93 caller_wait->Signal();
94 return;
97 surface_ = gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size(1, 1));
98 if (!surface_.get()) {
99 LOG(ERROR) << "Unable to create GLSurface";
100 caller_wait->Signal();
101 return;
104 // TODO(backer): This is coded for integrated GPUs. For discrete GPUs
105 // we would probably want to use a PBO texture upload for a true async
106 // upload (that would hopefully be optimized as a DMA transfer by the
107 // driver).
108 context_ = gfx::GLContext::CreateGLContext(parent_context->share_group(),
109 surface_.get(),
110 gfx::PreferIntegratedGpu);
111 if (!context_.get()) {
112 LOG(ERROR) << "Unable to create GLContext.";
113 caller_wait->Signal();
114 return;
117 context_->MakeCurrent(surface_.get());
118 initialized_ = true;
119 caller_wait->Signal();
122 DISALLOW_COPY_AND_ASSIGN(TransferThread);
125 base::LazyInstance<TransferThread>::Leaky
126 g_transfer_thread = LAZY_INSTANCE_INITIALIZER;
128 base::SingleThreadTaskRunner* transfer_task_runner() {
129 return g_transfer_thread.Pointer()->task_runner().get();
132 class PendingTask : public base::RefCountedThreadSafe<PendingTask> {
133 public:
134 explicit PendingTask(const base::Closure& task)
135 : task_(task), task_pending_(true, false) {}
137 bool TryRun() {
138 // This is meant to be called on the main thread where the texture
139 // is already bound.
140 DCHECK(checker_.CalledOnValidThread());
141 if (task_lock_.Try()) {
142 // Only run once.
143 if (!task_.is_null())
144 task_.Run();
145 task_.Reset();
147 task_lock_.Release();
148 task_pending_.Signal();
149 return true;
151 return false;
154 void BindAndRun(GLuint texture_id) {
155 // This is meant to be called on the upload thread where we don't have to
156 // restore the previous texture binding.
157 DCHECK(!checker_.CalledOnValidThread());
158 base::AutoLock locked(task_lock_);
159 if (!task_.is_null()) {
160 glBindTexture(GL_TEXTURE_2D, texture_id);
161 task_.Run();
162 task_.Reset();
163 glBindTexture(GL_TEXTURE_2D, 0);
164 // Flush for synchronization between threads.
165 glFlush();
166 task_pending_.Signal();
170 void Cancel() {
171 base::AutoLock locked(task_lock_);
172 task_.Reset();
173 task_pending_.Signal();
176 bool TaskIsInProgress() {
177 return !task_pending_.IsSignaled();
180 void WaitForTask() {
181 task_pending_.Wait();
184 private:
185 friend class base::RefCountedThreadSafe<PendingTask>;
187 virtual ~PendingTask() {}
189 base::ThreadChecker checker_;
191 base::Lock task_lock_;
192 base::Closure task_;
193 base::WaitableEvent task_pending_;
195 DISALLOW_COPY_AND_ASSIGN(PendingTask);
198 // Class which holds async pixel transfers state.
199 // The texture_id is accessed by either thread, but everything
200 // else accessed only on the main thread.
201 class TransferStateInternal
202 : public base::RefCountedThreadSafe<TransferStateInternal> {
203 public:
204 TransferStateInternal(GLuint texture_id,
205 const AsyncTexImage2DParams& define_params)
206 : texture_id_(texture_id), define_params_(define_params) {}
208 bool TransferIsInProgress() {
209 return pending_upload_task_.get() &&
210 pending_upload_task_->TaskIsInProgress();
213 void BindTransfer() {
214 TRACE_EVENT2("gpu", "BindAsyncTransfer",
215 "width", define_params_.width,
216 "height", define_params_.height);
217 DCHECK(texture_id_);
219 glBindTexture(GL_TEXTURE_2D, texture_id_);
220 bind_callback_.Run();
223 void WaitForTransferCompletion() {
224 TRACE_EVENT0("gpu", "WaitForTransferCompletion");
225 DCHECK(pending_upload_task_.get());
226 if (!pending_upload_task_->TryRun()) {
227 pending_upload_task_->WaitForTask();
229 pending_upload_task_ = NULL;
232 void CancelUpload() {
233 TRACE_EVENT0("gpu", "CancelUpload");
234 if (pending_upload_task_.get())
235 pending_upload_task_->Cancel();
236 pending_upload_task_ = NULL;
239 void ScheduleAsyncTexImage2D(
240 const AsyncTexImage2DParams tex_params,
241 const AsyncMemoryParams mem_params,
242 scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats,
243 const base::Closure& bind_callback) {
244 TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("gpu.AsyncTexImage");
245 pending_upload_task_ = new PendingTask(base::Bind(
246 &TransferStateInternal::PerformAsyncTexImage2D,
247 this,
248 tex_params,
249 mem_params,
250 texture_upload_stats));
251 transfer_task_runner()->PostTask(
252 FROM_HERE, base::Bind(&PendingTask::BindAndRun, pending_upload_task_,
253 texture_id_));
255 // Save the late bind callback, so we can notify the client when it is
256 // bound.
257 bind_callback_ = bind_callback;
260 void ScheduleAsyncTexSubImage2D(
261 AsyncTexSubImage2DParams tex_params,
262 AsyncMemoryParams mem_params,
263 scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) {
264 TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("gpu.AsyncTexImage");
265 pending_upload_task_ = new PendingTask(base::Bind(
266 &TransferStateInternal::PerformAsyncTexSubImage2D,
267 this,
268 tex_params,
269 mem_params,
270 texture_upload_stats));
271 transfer_task_runner()->PostTask(
272 FROM_HERE, base::Bind(&PendingTask::BindAndRun, pending_upload_task_,
273 texture_id_));
276 private:
277 friend class base::RefCountedThreadSafe<TransferStateInternal>;
279 virtual ~TransferStateInternal() {
282 void PerformAsyncTexImage2D(
283 AsyncTexImage2DParams tex_params,
284 AsyncMemoryParams mem_params,
285 scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) {
286 TRACE_EVENT2("gpu",
287 "PerformAsyncTexImage",
288 "width",
289 tex_params.width,
290 "height",
291 tex_params.height);
292 DCHECK_EQ(0, tex_params.level);
294 base::TimeTicks begin_time;
295 if (texture_upload_stats.get())
296 begin_time = base::TimeTicks::Now();
298 void* data = mem_params.GetDataAddress();
301 TRACE_EVENT0("gpu", "glTexImage2D");
302 glTexImage2D(GL_TEXTURE_2D,
303 tex_params.level,
304 tex_params.internal_format,
305 tex_params.width,
306 tex_params.height,
307 tex_params.border,
308 tex_params.format,
309 tex_params.type,
310 data);
311 TRACE_EVENT_SYNTHETIC_DELAY_END("gpu.AsyncTexImage");
314 if (texture_upload_stats.get()) {
315 texture_upload_stats->AddUpload(base::TimeTicks::Now() - begin_time);
319 void PerformAsyncTexSubImage2D(
320 AsyncTexSubImage2DParams tex_params,
321 AsyncMemoryParams mem_params,
322 scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) {
323 TRACE_EVENT2("gpu",
324 "PerformAsyncTexSubImage2D",
325 "width",
326 tex_params.width,
327 "height",
328 tex_params.height);
329 DCHECK_EQ(0, tex_params.level);
331 base::TimeTicks begin_time;
332 if (texture_upload_stats.get())
333 begin_time = base::TimeTicks::Now();
335 void* data = mem_params.GetDataAddress();
337 TRACE_EVENT0("gpu", "glTexSubImage2D");
338 glTexSubImage2D(GL_TEXTURE_2D,
339 tex_params.level,
340 tex_params.xoffset,
341 tex_params.yoffset,
342 tex_params.width,
343 tex_params.height,
344 tex_params.format,
345 tex_params.type,
346 data);
347 TRACE_EVENT_SYNTHETIC_DELAY_END("gpu.AsyncTexImage");
350 if (texture_upload_stats.get()) {
351 texture_upload_stats->AddUpload(base::TimeTicks::Now() - begin_time);
355 scoped_refptr<PendingTask> pending_upload_task_;
357 GLuint texture_id_;
359 // Definition params for texture that needs binding.
360 AsyncTexImage2DParams define_params_;
362 // Callback to invoke when AsyncTexImage2D is complete
363 // and the client can safely use the texture. This occurs
364 // during BindCompletedAsyncTransfers().
365 base::Closure bind_callback_;
368 } // namespace
370 class AsyncPixelTransferDelegateShareGroup
371 : public AsyncPixelTransferDelegate,
372 public base::SupportsWeakPtr<AsyncPixelTransferDelegateShareGroup> {
373 public:
374 AsyncPixelTransferDelegateShareGroup(
375 AsyncPixelTransferManagerShareGroup::SharedState* shared_state,
376 GLuint texture_id,
377 const AsyncTexImage2DParams& define_params);
378 ~AsyncPixelTransferDelegateShareGroup() override;
380 void BindTransfer() { state_->BindTransfer(); }
382 // Implement AsyncPixelTransferDelegate:
383 void AsyncTexImage2D(const AsyncTexImage2DParams& tex_params,
384 const AsyncMemoryParams& mem_params,
385 const base::Closure& bind_callback) override;
386 void AsyncTexSubImage2D(const AsyncTexSubImage2DParams& tex_params,
387 const AsyncMemoryParams& mem_params) override;
388 bool TransferIsInProgress() override;
389 void WaitForTransferCompletion() override;
391 private:
392 // A raw pointer is safe because the SharedState is owned by the Manager,
393 // which owns this Delegate.
394 AsyncPixelTransferManagerShareGroup::SharedState* shared_state_;
395 scoped_refptr<TransferStateInternal> state_;
397 DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateShareGroup);
400 AsyncPixelTransferDelegateShareGroup::AsyncPixelTransferDelegateShareGroup(
401 AsyncPixelTransferManagerShareGroup::SharedState* shared_state,
402 GLuint texture_id,
403 const AsyncTexImage2DParams& define_params)
404 : shared_state_(shared_state),
405 state_(new TransferStateInternal(texture_id, define_params)) {}
407 AsyncPixelTransferDelegateShareGroup::~AsyncPixelTransferDelegateShareGroup() {
408 TRACE_EVENT0("gpu", " ~AsyncPixelTransferDelegateShareGroup");
409 state_->CancelUpload();
412 bool AsyncPixelTransferDelegateShareGroup::TransferIsInProgress() {
413 return state_->TransferIsInProgress();
416 void AsyncPixelTransferDelegateShareGroup::WaitForTransferCompletion() {
417 if (state_->TransferIsInProgress()) {
418 state_->WaitForTransferCompletion();
419 DCHECK(!state_->TransferIsInProgress());
422 // Fast track the BindTransfer, if applicable.
423 for (AsyncPixelTransferManagerShareGroup::SharedState::TransferQueue::iterator
424 iter = shared_state_->pending_allocations.begin();
425 iter != shared_state_->pending_allocations.end();
426 ++iter) {
427 if (iter->get() != this)
428 continue;
430 shared_state_->pending_allocations.erase(iter);
431 BindTransfer();
432 break;
436 void AsyncPixelTransferDelegateShareGroup::AsyncTexImage2D(
437 const AsyncTexImage2DParams& tex_params,
438 const AsyncMemoryParams& mem_params,
439 const base::Closure& bind_callback) {
440 DCHECK(!state_->TransferIsInProgress());
441 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
442 DCHECK_EQ(tex_params.level, 0);
444 shared_state_->pending_allocations.push_back(AsWeakPtr());
445 state_->ScheduleAsyncTexImage2D(tex_params,
446 mem_params,
447 shared_state_->texture_upload_stats,
448 bind_callback);
451 void AsyncPixelTransferDelegateShareGroup::AsyncTexSubImage2D(
452 const AsyncTexSubImage2DParams& tex_params,
453 const AsyncMemoryParams& mem_params) {
454 TRACE_EVENT2("gpu", "AsyncTexSubImage2D",
455 "width", tex_params.width,
456 "height", tex_params.height);
457 DCHECK(!state_->TransferIsInProgress());
458 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
459 DCHECK_EQ(tex_params.level, 0);
461 state_->ScheduleAsyncTexSubImage2D(
462 tex_params, mem_params, shared_state_->texture_upload_stats);
465 AsyncPixelTransferManagerShareGroup::SharedState::SharedState()
466 // TODO(reveman): Skip this if --enable-gpu-benchmarking is not present.
467 : texture_upload_stats(new AsyncPixelTransferUploadStats) {}
469 AsyncPixelTransferManagerShareGroup::SharedState::~SharedState() {}
471 AsyncPixelTransferManagerShareGroup::AsyncPixelTransferManagerShareGroup(
472 gfx::GLContext* context) {
473 g_transfer_thread.Pointer()->InitializeOnMainThread(context);
476 AsyncPixelTransferManagerShareGroup::~AsyncPixelTransferManagerShareGroup() {}
478 void AsyncPixelTransferManagerShareGroup::BindCompletedAsyncTransfers() {
479 scoped_ptr<gfx::ScopedTextureBinder> texture_binder;
481 while (!shared_state_.pending_allocations.empty()) {
482 if (!shared_state_.pending_allocations.front().get()) {
483 shared_state_.pending_allocations.pop_front();
484 continue;
486 AsyncPixelTransferDelegateShareGroup* delegate =
487 shared_state_.pending_allocations.front().get();
488 // Terminate early, as all transfers finish in order, currently.
489 if (delegate->TransferIsInProgress())
490 break;
492 if (!texture_binder)
493 texture_binder.reset(new gfx::ScopedTextureBinder(GL_TEXTURE_2D, 0));
495 // Used to set tex info from the gles2 cmd decoder once upload has
496 // finished (it'll bind the texture and call a callback).
497 delegate->BindTransfer();
499 shared_state_.pending_allocations.pop_front();
503 void AsyncPixelTransferManagerShareGroup::AsyncNotifyCompletion(
504 const AsyncMemoryParams& mem_params,
505 AsyncPixelTransferCompletionObserver* observer) {
506 // Post a PerformNotifyCompletion task to the upload thread. This task
507 // will run after all async transfers are complete.
508 transfer_task_runner()->PostTask(
509 FROM_HERE, base::Bind(&PerformNotifyCompletion, mem_params,
510 make_scoped_refptr(observer)));
513 uint32 AsyncPixelTransferManagerShareGroup::GetTextureUploadCount() {
514 return shared_state_.texture_upload_stats->GetStats(NULL);
517 base::TimeDelta
518 AsyncPixelTransferManagerShareGroup::GetTotalTextureUploadTime() {
519 base::TimeDelta total_texture_upload_time;
520 shared_state_.texture_upload_stats->GetStats(&total_texture_upload_time);
521 return total_texture_upload_time;
524 void AsyncPixelTransferManagerShareGroup::ProcessMorePendingTransfers() {
527 bool AsyncPixelTransferManagerShareGroup::NeedsProcessMorePendingTransfers() {
528 return false;
531 void AsyncPixelTransferManagerShareGroup::WaitAllAsyncTexImage2D() {
532 if (shared_state_.pending_allocations.empty())
533 return;
535 AsyncPixelTransferDelegateShareGroup* delegate =
536 shared_state_.pending_allocations.back().get();
537 if (delegate)
538 delegate->WaitForTransferCompletion();
541 AsyncPixelTransferDelegate*
542 AsyncPixelTransferManagerShareGroup::CreatePixelTransferDelegateImpl(
543 gles2::TextureRef* ref,
544 const AsyncTexImage2DParams& define_params) {
545 return new AsyncPixelTransferDelegateShareGroup(
546 &shared_state_, ref->service_id(), define_params);
549 } // namespace gpu