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

Side by Side Diff: gpu/command_buffer/service/async_pixel_transfer_delegate_share_group.cc

Issue 16325018: GPU: Factory produces APTManagers instead of APTDelegates (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 6 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 | Annotate | Revision Log
OLDNEW
(Empty)
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/async_pixel_transfer_delegate_share_group.h "
6
7 #include "base/bind.h"
8 #include "base/debug/trace_event.h"
9 #include "base/lazy_instance.h"
10 #include "base/logging.h"
11 #include "base/synchronization/cancellation_flag.h"
12 #include "base/synchronization/lock.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/threading/thread.h"
15 #include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
16 #include "gpu/command_buffer/service/safe_shared_memory_pool.h"
17 #include "ui/gl/gl_bindings.h"
18 #include "ui/gl/gl_context.h"
19 #include "ui/gl/gl_surface.h"
20 #include "ui/gl/gpu_preference.h"
21 #include "ui/gl/scoped_binders.h"
22
23 namespace gpu {
24
25 namespace {
26
27 const char kAsyncTransferThreadName[] = "AsyncTransferThread";
28
29 // TODO(backer): Factor out common thread scheduling logic from the EGL and
30 // ShareGroup implementations. http://crbug.com/239889
31 class TransferThread : public base::Thread {
32 public:
33 TransferThread()
34 : base::Thread(kAsyncTransferThreadName),
35 initialized_(false) {
36 Start();
37 #if defined(OS_ANDROID) || defined(OS_LINUX)
38 SetPriority(base::kThreadPriority_Background);
39 #endif
40 }
41
42 virtual ~TransferThread() {
43 // The only instance of this class was declared leaky.
44 NOTREACHED();
45 }
46
47 void InitializeOnMainThread(gfx::GLContext* parent_context) {
48 TRACE_EVENT0("gpu", "TransferThread::InitializeOnMainThread");
49 if (initialized_)
50 return;
51
52 base::WaitableEvent wait_for_init(true, false);
53 message_loop_proxy()->PostTask(
54 FROM_HERE,
55 base::Bind(&TransferThread::InitializeOnTransferThread,
56 base::Unretained(this),
57 base::Unretained(parent_context),
58 &wait_for_init));
59 wait_for_init.Wait();
60 }
61
62 virtual void CleanUp() OVERRIDE {
63 surface_ = NULL;
64 context_ = NULL;
65 }
66
67 SafeSharedMemoryPool* safe_shared_memory_pool() {
68 return &safe_shared_memory_pool_;
69 }
70
71 private:
72 bool initialized_;
73
74 scoped_refptr<gfx::GLSurface> surface_;
75 scoped_refptr<gfx::GLContext> context_;
76 SafeSharedMemoryPool safe_shared_memory_pool_;
77
78 void InitializeOnTransferThread(gfx::GLContext* parent_context,
79 base::WaitableEvent* caller_wait) {
80 TRACE_EVENT0("gpu", "InitializeOnTransferThread");
81
82 if (!parent_context) {
83 LOG(ERROR) << "No parent context provided.";
84 caller_wait->Signal();
85 return;
86 }
87
88 surface_ = gfx::GLSurface::CreateOffscreenGLSurface(false, gfx::Size(1, 1));
89 if (!surface_) {
90 LOG(ERROR) << "Unable to create GLSurface";
91 caller_wait->Signal();
92 return;
93 }
94
95 // TODO(backer): This is coded for integrated GPUs. For discrete GPUs
96 // we would probably want to use a PBO texture upload for a true async
97 // upload (that would hopefully be optimized as a DMA transfer by the
98 // driver).
99 context_ = gfx::GLContext::CreateGLContext(parent_context->share_group(),
100 surface_,
101 gfx::PreferIntegratedGpu);
102 if (!context_) {
103 LOG(ERROR) << "Unable to create GLContext.";
104 caller_wait->Signal();
105 return;
106 }
107
108 context_->MakeCurrent(surface_);
109 initialized_ = true;
110 caller_wait->Signal();
111 }
112
113 DISALLOW_COPY_AND_ASSIGN(TransferThread);
114 };
115
116 base::LazyInstance<TransferThread>::Leaky
117 g_transfer_thread = LAZY_INSTANCE_INITIALIZER;
118
119 base::MessageLoopProxy* transfer_message_loop_proxy() {
120 return g_transfer_thread.Pointer()->message_loop_proxy();
121 }
122
123 SafeSharedMemoryPool* safe_shared_memory_pool() {
124 return g_transfer_thread.Pointer()->safe_shared_memory_pool();
125 }
126
127 // Class which holds async pixel transfers state.
128 // The texture_id is accessed by either thread, but everything
129 // else accessed only on the main thread.
130 class TransferStateInternal
131 : public base::RefCountedThreadSafe<TransferStateInternal> {
132 public:
133 TransferStateInternal(GLuint texture_id,
134 const AsyncTexImage2DParams& define_params)
135 : texture_id_(texture_id),
136 transfer_completion_(true, true) {
137 define_params_ = define_params;
138 }
139
140 // Implement AsyncPixelTransferState:
141 bool TransferIsInProgress() {
142 return !transfer_completion_.IsSignaled();
143 }
144
145 void BindTransfer() {
146 TRACE_EVENT2("gpu", "BindAsyncTransfer",
147 "width", define_params_.width,
148 "height", define_params_.height);
149 DCHECK(texture_id_);
150
151 glBindTexture(GL_TEXTURE_2D, texture_id_);
152 bind_callback_.Run();
153 }
154
155 void MarkAsTransferIsInProgress() {
156 transfer_completion_.Reset();
157 }
158
159 void MarkAsCompleted() {
160 TRACE_EVENT0("gpu", "MarkAsCompleted");
161 glFlush();
162 transfer_completion_.Signal();
163 }
164
165 void WaitForTransferCompletion() {
166 TRACE_EVENT0("gpu", "WaitForTransferCompletion");
167 // TODO(backer): Deschedule the channel rather than blocking the main GPU
168 // thread (crbug.com/240265).
169 transfer_completion_.Wait();
170 }
171
172 GLuint texture_id() { return texture_id_; }
173
174 void SetBindCallback(base::Closure bind_callback) {
175 bind_callback_ = bind_callback;
176 }
177
178 void PerformAsyncTexImage2D(AsyncTexImage2DParams tex_params,
179 AsyncMemoryParams mem_params,
180 ScopedSafeSharedMemory* safe_shared_memory) {
181 base::AutoLock locked(upload_lock_);
182 if (cancel_upload_flag_.IsSet())
183 return;
184
185 TRACE_EVENT2("gpu",
186 "PerformAsyncTexImage",
187 "width",
188 tex_params.width,
189 "height",
190 tex_params.height);
191 DCHECK_EQ(0, tex_params.level);
192
193 void* data =
194 AsyncPixelTransferDelegate::GetAddress(safe_shared_memory, mem_params);
195
196 {
197 TRACE_EVENT0("gpu", "glTexImage2D");
198 glBindTexture(GL_TEXTURE_2D, texture_id_);
199 glTexImage2D(GL_TEXTURE_2D,
200 tex_params.level,
201 tex_params.internal_format,
202 tex_params.width,
203 tex_params.height,
204 tex_params.border,
205 tex_params.format,
206 tex_params.type,
207 data);
208 glBindTexture(GL_TEXTURE_2D, 0);
209 }
210
211 MarkAsCompleted();
212 }
213
214 void PerformAsyncTexSubImage2D(
215 AsyncTexSubImage2DParams tex_params,
216 AsyncMemoryParams mem_params,
217 ScopedSafeSharedMemory* safe_shared_memory,
218 scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) {
219 base::AutoLock locked(upload_lock_);
220 if (cancel_upload_flag_.IsSet())
221 return;
222
223 TRACE_EVENT2("gpu",
224 "PerformAsyncTexSubImage2D",
225 "width",
226 tex_params.width,
227 "height",
228 tex_params.height);
229 DCHECK_EQ(0, tex_params.level);
230
231 base::TimeTicks begin_time;
232 if (texture_upload_stats)
233 begin_time = base::TimeTicks::HighResNow();
234
235 void* data =
236 AsyncPixelTransferDelegate::GetAddress(safe_shared_memory, mem_params);
237
238 {
239 TRACE_EVENT0("gpu", "glTexSubImage2D");
240 glBindTexture(GL_TEXTURE_2D, texture_id_);
241 glTexSubImage2D(GL_TEXTURE_2D,
242 tex_params.level,
243 tex_params.xoffset,
244 tex_params.yoffset,
245 tex_params.width,
246 tex_params.height,
247 tex_params.format,
248 tex_params.type,
249 data);
250 glBindTexture(GL_TEXTURE_2D, 0);
251 }
252
253 MarkAsCompleted();
254
255 if (texture_upload_stats) {
256 texture_upload_stats->AddUpload(base::TimeTicks::HighResNow() -
257 begin_time);
258 }
259 }
260
261 base::CancellationFlag* cancel_upload_flag() { return &cancel_upload_flag_; }
262 base::Lock* upload_lock() { return &upload_lock_; }
263
264 private:
265 friend class base::RefCountedThreadSafe<TransferStateInternal>;
266
267 virtual ~TransferStateInternal() {
268 }
269
270 // Used to cancel pending uploads.
271 base::CancellationFlag cancel_upload_flag_;
272 base::Lock upload_lock_;
273
274 GLuint texture_id_;
275
276 // Definition params for texture that needs binding.
277 AsyncTexImage2DParams define_params_;
278
279 // Indicates that an async transfer is in progress.
280 base::WaitableEvent transfer_completion_;
281
282 // Callback to invoke when AsyncTexImage2D is complete
283 // and the client can safely use the texture. This occurs
284 // during BindCompletedAsyncTransfers().
285 base::Closure bind_callback_;
286 };
287
288 void PerformNotifyCompletion(
289 AsyncMemoryParams mem_params,
290 ScopedSafeSharedMemory* safe_shared_memory,
291 const AsyncPixelTransferDelegate::CompletionCallback& callback) {
292 TRACE_EVENT0("gpu", "PerformNotifyCompletion");
293 AsyncMemoryParams safe_mem_params = mem_params;
294 safe_mem_params.shared_memory = safe_shared_memory->shared_memory();
295 callback.Run(safe_mem_params);
296 }
297
298 } // namespace
299
300 // ShareGroup needs thread-safe ref-counting, so this just wraps
301 // an internal thread-safe ref-counted state object.
302 class AsyncTransferStateImpl : public AsyncPixelTransferState {
303 public:
304 AsyncTransferStateImpl(GLuint texture_id,
305 const AsyncTexImage2DParams& define_params)
306 : internal_(new TransferStateInternal(texture_id, define_params)) {}
307
308 virtual bool TransferIsInProgress() OVERRIDE {
309 return internal_->TransferIsInProgress();
310 }
311
312 TransferStateInternal* internal() { return internal_.get(); }
313
314 private:
315 virtual ~AsyncTransferStateImpl() {
316 TRACE_EVENT0("gpu", " ~AsyncTransferStateImpl");
317 base::AutoLock locked(*internal_->upload_lock());
318 internal_->cancel_upload_flag()->Set();
319 }
320
321 scoped_refptr<TransferStateInternal> internal_;
322 };
323
324 AsyncPixelTransferDelegateShareGroup::AsyncPixelTransferDelegateShareGroup(
325 gfx::GLContext* context) {
326 g_transfer_thread.Pointer()->InitializeOnMainThread(context);
327
328 // TODO(reveman): Skip this if --enable-gpu-benchmarking is not present.
329 texture_upload_stats_ = make_scoped_refptr(new AsyncPixelTransferUploadStats);
330 }
331
332 AsyncPixelTransferDelegateShareGroup::~AsyncPixelTransferDelegateShareGroup() {
333 }
334
335 AsyncPixelTransferState*
336 AsyncPixelTransferDelegateShareGroup::
337 CreatePixelTransferState(
338 GLuint texture_id,
339 const AsyncTexImage2DParams& define_params) {
340 return static_cast<AsyncPixelTransferState*>(
341 new AsyncTransferStateImpl(texture_id, define_params));
342 }
343
344 void AsyncPixelTransferDelegateShareGroup::BindCompletedAsyncTransfers() {
345 scoped_ptr<gfx::ScopedTextureBinder> texture_binder;
346
347 while (!pending_allocations_.empty()) {
348 if (!pending_allocations_.front().get()) {
349 pending_allocations_.pop_front();
350 continue;
351 }
352 scoped_refptr<TransferStateInternal> state =
353 static_cast<AsyncTransferStateImpl*>
354 (pending_allocations_.front().get())->internal();
355 // Terminate early, as all transfers finish in order, currently.
356 if (state->TransferIsInProgress())
357 break;
358
359 if (!texture_binder)
360 texture_binder.reset(new gfx::ScopedTextureBinder(GL_TEXTURE_2D, 0));
361
362 // Used to set tex info from the gles2 cmd decoder once upload has
363 // finished (it'll bind the texture and call a callback).
364 state->BindTransfer();
365
366 pending_allocations_.pop_front();
367 }
368 }
369
370 void AsyncPixelTransferDelegateShareGroup::AsyncNotifyCompletion(
371 const AsyncMemoryParams& mem_params,
372 const CompletionCallback& callback) {
373 DCHECK(mem_params.shared_memory);
374 DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
375 mem_params.shm_size);
376 // Post a PerformNotifyCompletion task to the upload thread. This task
377 // will run after all async transfers are complete.
378 transfer_message_loop_proxy()->PostTask(
379 FROM_HERE,
380 base::Bind(&PerformNotifyCompletion,
381 mem_params,
382 base::Owned(
383 new ScopedSafeSharedMemory(safe_shared_memory_pool(),
384 mem_params.shared_memory,
385 mem_params.shm_size)),
386 callback));
387 }
388
389 void AsyncPixelTransferDelegateShareGroup::WaitForTransferCompletion(
390 AsyncPixelTransferState* transfer_state) {
391 scoped_refptr<TransferStateInternal> state =
392 static_cast<AsyncTransferStateImpl*>(transfer_state)->internal();
393 DCHECK(state);
394 DCHECK(state->texture_id());
395
396 if (state->TransferIsInProgress()) {
397 #if defined(OS_ANDROID) || defined(OS_LINUX)
398 g_transfer_thread.Pointer()->SetPriority(base::kThreadPriority_Display);
399 #endif
400
401 state->WaitForTransferCompletion();
402 DCHECK(!state->TransferIsInProgress());
403
404 #if defined(OS_ANDROID) || defined(OS_LINUX)
405 g_transfer_thread.Pointer()->SetPriority(base::kThreadPriority_Background);
406 #endif
407 }
408 }
409
410 void AsyncPixelTransferDelegateShareGroup::AsyncTexImage2D(
411 AsyncPixelTransferState* transfer_state,
412 const AsyncTexImage2DParams& tex_params,
413 const AsyncMemoryParams& mem_params,
414 const base::Closure& bind_callback) {
415 scoped_refptr<TransferStateInternal> state =
416 static_cast<AsyncTransferStateImpl*>(transfer_state)->internal();
417 DCHECK(mem_params.shared_memory);
418 DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
419 mem_params.shm_size);
420 DCHECK(state);
421 DCHECK(state->texture_id());
422 DCHECK(!state->TransferIsInProgress());
423 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
424 DCHECK_EQ(tex_params.level, 0);
425
426 // Mark the transfer in progress and save the late bind
427 // callback, so we can notify the client when it is bound.
428 pending_allocations_.push_back(transfer_state->AsWeakPtr());
429 state->SetBindCallback(bind_callback);
430
431 // Mark the transfer in progress.
432 state->MarkAsTransferIsInProgress();
433
434 // Duplicate the shared memory so there is no way we can get
435 // a use-after-free of the raw pixels.
436 transfer_message_loop_proxy()->PostTask(
437 FROM_HERE,
438 base::Bind(
439 &TransferStateInternal::PerformAsyncTexImage2D,
440 state,
441 tex_params,
442 mem_params,
443 base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
444 mem_params.shared_memory,
445 mem_params.shm_size))));
446 }
447
448 void AsyncPixelTransferDelegateShareGroup::AsyncTexSubImage2D(
449 AsyncPixelTransferState* transfer_state,
450 const AsyncTexSubImage2DParams& tex_params,
451 const AsyncMemoryParams& mem_params) {
452 TRACE_EVENT2("gpu", "AsyncTexSubImage2D",
453 "width", tex_params.width,
454 "height", tex_params.height);
455 scoped_refptr<TransferStateInternal> state =
456 static_cast<AsyncTransferStateImpl*>(transfer_state)->internal();
457
458 DCHECK(state->texture_id());
459 DCHECK(!state->TransferIsInProgress());
460 DCHECK(mem_params.shared_memory);
461 DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
462 mem_params.shm_size);
463 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
464 DCHECK_EQ(tex_params.level, 0);
465
466 // Mark the transfer in progress.
467 state->MarkAsTransferIsInProgress();
468
469 // Duplicate the shared memory so there are no way we can get
470 // a use-after-free of the raw pixels.
471 transfer_message_loop_proxy()->PostTask(
472 FROM_HERE,
473 base::Bind(
474 &TransferStateInternal::PerformAsyncTexSubImage2D,
475 state,
476 tex_params,
477 mem_params,
478 base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
479 mem_params.shared_memory,
480 mem_params.shm_size)),
481 texture_upload_stats_));
482 }
483
484 uint32 AsyncPixelTransferDelegateShareGroup::GetTextureUploadCount() {
485 DCHECK(texture_upload_stats_);
486 return texture_upload_stats_->GetStats(NULL);
487 }
488
489 base::TimeDelta
490 AsyncPixelTransferDelegateShareGroup::GetTotalTextureUploadTime() {
491 DCHECK(texture_upload_stats_);
492 base::TimeDelta total_texture_upload_time;
493 texture_upload_stats_->GetStats(&total_texture_upload_time);
494 return total_texture_upload_time;
495 }
496
497 void AsyncPixelTransferDelegateShareGroup::ProcessMorePendingTransfers() {
498 }
499
500 bool AsyncPixelTransferDelegateShareGroup::NeedsProcessMorePendingTransfers() {
501 return false;
502 }
503
504 } // namespace gpu
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698