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

Side by Side Diff: gpu/command_buffer/service/async_pixel_transfer_delegate_egl.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 (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "gpu/command_buffer/service/async_pixel_transfer_delegate_egl.h"
6
7 #include <string>
8
9 #include "base/bind.h"
10 #include "base/debug/trace_event.h"
11 #include "base/lazy_instance.h"
12 #include "base/logging.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/synchronization/waitable_event.h"
15 #include "base/threading/thread.h"
16 #include "gpu/command_buffer/service/safe_shared_memory_pool.h"
17 #include "ui/gl/gl_context.h"
18 #include "ui/gl/gl_surface_egl.h"
19 #include "ui/gl/scoped_binders.h"
20
21 namespace gpu {
22
23 namespace {
24
25 bool CheckErrors(const char* file, int line) {
26 EGLint eglerror;
27 GLenum glerror;
28 bool success = true;
29 while ((eglerror = eglGetError()) != EGL_SUCCESS) {
30 LOG(ERROR) << "Async transfer EGL error at "
31 << file << ":" << line << " " << eglerror;
32 success = false;
33 }
34 while ((glerror = glGetError()) != GL_NO_ERROR) {
35 LOG(ERROR) << "Async transfer OpenGL error at "
36 << file << ":" << line << " " << glerror;
37 success = false;
38 }
39 return success;
40 }
41 #define CHECK_GL() CheckErrors(__FILE__, __LINE__)
42
43 const char kAsyncTransferThreadName[] = "AsyncTransferThread";
44
45 // Regular glTexImage2D call.
46 void DoTexImage2D(const AsyncTexImage2DParams& tex_params, void* data) {
47 glTexImage2D(
48 GL_TEXTURE_2D, tex_params.level, tex_params.internal_format,
49 tex_params.width, tex_params.height,
50 tex_params.border, tex_params.format, tex_params.type, data);
51 }
52
53 // Regular glTexSubImage2D call.
54 void DoTexSubImage2D(const AsyncTexSubImage2DParams& tex_params, void* data) {
55 glTexSubImage2D(
56 GL_TEXTURE_2D, tex_params.level,
57 tex_params.xoffset, tex_params.yoffset,
58 tex_params.width, tex_params.height,
59 tex_params.format, tex_params.type, data);
60 }
61
62 // Full glTexSubImage2D call, from glTexImage2D params.
63 void DoFullTexSubImage2D(const AsyncTexImage2DParams& tex_params, void* data) {
64 glTexSubImage2D(
65 GL_TEXTURE_2D, tex_params.level,
66 0, 0, tex_params.width, tex_params.height,
67 tex_params.format, tex_params.type, data);
68 }
69
70 void SetGlParametersForEglImageTexture() {
71 // These params are needed for EGLImage creation to succeed on several
72 // Android devices. I couldn't find this requirement in the EGLImage
73 // extension spec, but several devices fail without it.
74 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
75 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
76 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
77 }
78
79 class TransferThread : public base::Thread {
80 public:
81 TransferThread() : base::Thread(kAsyncTransferThreadName) {
82 Start();
83 #if defined(OS_ANDROID) || defined(OS_LINUX)
84 SetPriority(base::kThreadPriority_Background);
85 #endif
86 }
87 virtual ~TransferThread() {
88 Stop();
89 }
90
91 virtual void Init() OVERRIDE {
92 gfx::GLShareGroup* share_group = NULL;
93 bool software = false;
94 surface_ = new gfx::PbufferGLSurfaceEGL(software, gfx::Size(1,1));
95 surface_->Initialize();
96 context_ = gfx::GLContext::CreateGLContext(share_group,
97 surface_,
98 gfx::PreferDiscreteGpu);
99 bool is_current = context_->MakeCurrent(surface_);
100 DCHECK(is_current);
101 }
102
103 virtual void CleanUp() OVERRIDE {
104 surface_ = NULL;
105 context_->ReleaseCurrent(surface_);
106 context_ = NULL;
107 }
108
109 SafeSharedMemoryPool* safe_shared_memory_pool() {
110 return &safe_shared_memory_pool_;
111 }
112
113 private:
114 scoped_refptr<gfx::GLContext> context_;
115 scoped_refptr<gfx::GLSurface> surface_;
116
117 SafeSharedMemoryPool safe_shared_memory_pool_;
118
119 DISALLOW_COPY_AND_ASSIGN(TransferThread);
120 };
121
122 base::LazyInstance<TransferThread>
123 g_transfer_thread = LAZY_INSTANCE_INITIALIZER;
124
125 base::MessageLoopProxy* transfer_message_loop_proxy() {
126 return g_transfer_thread.Pointer()->message_loop_proxy();
127 }
128
129 SafeSharedMemoryPool* safe_shared_memory_pool() {
130 return g_transfer_thread.Pointer()->safe_shared_memory_pool();
131 }
132
133 // Class which holds async pixel transfers state (EGLImage).
134 // The EGLImage is accessed by either thread, but everything
135 // else accessed only on the main thread.
136 class TransferStateInternal
137 : public base::RefCountedThreadSafe<TransferStateInternal> {
138 public:
139 TransferStateInternal(GLuint texture_id,
140 const AsyncTexImage2DParams& define_params,
141 bool wait_for_uploads,
142 bool wait_for_creation,
143 bool use_image_preserved)
144 : texture_id_(texture_id),
145 thread_texture_id_(0),
146 transfer_completion_(true, true),
147 egl_image_(EGL_NO_IMAGE_KHR),
148 wait_for_uploads_(wait_for_uploads),
149 wait_for_creation_(wait_for_creation),
150 use_image_preserved_(use_image_preserved) {
151 define_params_ = define_params;
152 }
153
154 bool TransferIsInProgress() {
155 return !transfer_completion_.IsSignaled();
156 }
157
158 void BindTransfer() {
159 TRACE_EVENT2("gpu", "BindAsyncTransfer glEGLImageTargetTexture2DOES",
160 "width", define_params_.width,
161 "height", define_params_.height);
162 DCHECK(texture_id_);
163 DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_);
164
165 glBindTexture(GL_TEXTURE_2D, texture_id_);
166 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_);
167 bind_callback_.Run();
168
169 DCHECK(CHECK_GL());
170 }
171
172 void CreateEglImage(GLuint texture_id) {
173 TRACE_EVENT0("gpu", "eglCreateImageKHR");
174 DCHECK(texture_id);
175 DCHECK_EQ(egl_image_, EGL_NO_IMAGE_KHR);
176
177 EGLDisplay egl_display = eglGetCurrentDisplay();
178 EGLContext egl_context = eglGetCurrentContext();
179 EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR;
180 EGLClientBuffer egl_buffer =
181 reinterpret_cast<EGLClientBuffer>(texture_id);
182
183 EGLint image_preserved = use_image_preserved_ ? EGL_TRUE : EGL_FALSE;
184 EGLint egl_attrib_list[] = {
185 EGL_GL_TEXTURE_LEVEL_KHR, 0, // mip-level.
186 EGL_IMAGE_PRESERVED_KHR, image_preserved,
187 EGL_NONE
188 };
189 egl_image_ = eglCreateImageKHR(
190 egl_display,
191 egl_context,
192 egl_target,
193 egl_buffer,
194 egl_attrib_list);
195
196 DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_);
197 }
198
199 void CreateEglImageOnUploadThread() {
200 CreateEglImage(thread_texture_id_);
201 }
202
203 void CreateEglImageOnMainThreadIfNeeded() {
204 if (egl_image_ == EGL_NO_IMAGE_KHR) {
205 CreateEglImage(texture_id_);
206 if (wait_for_creation_) {
207 TRACE_EVENT0("gpu", "glFinish creation");
208 glFinish();
209 }
210 }
211 }
212
213 void WaitForLastUpload() {
214 // This glFinish is just a safe-guard for if uploads have some
215 // GPU action that needs to occur. We could use fences and try
216 // to do this less often. However, on older drivers fences are
217 // not always reliable (eg. Mali-400 just blocks forever).
218 if (wait_for_uploads_) {
219 TRACE_EVENT0("gpu", "glFinish");
220 glFinish();
221 }
222 }
223
224 void MarkAsTransferIsInProgress() {
225 transfer_completion_.Reset();
226 }
227
228 void MarkAsCompleted() {
229 transfer_completion_.Signal();
230 }
231
232 void WaitForTransferCompletion() {
233 TRACE_EVENT0("gpu", "WaitForTransferCompletion");
234 // TODO(backer): Deschedule the channel rather than blocking the main GPU
235 // thread (crbug.com/240265).
236 transfer_completion_.Wait();
237 }
238
239 void PerformAsyncTexImage2D(AsyncTexImage2DParams tex_params,
240 AsyncMemoryParams mem_params,
241 ScopedSafeSharedMemory* safe_shared_memory) {
242 TRACE_EVENT2("gpu",
243 "PerformAsyncTexImage",
244 "width",
245 tex_params.width,
246 "height",
247 tex_params.height);
248 DCHECK(!thread_texture_id_);
249 DCHECK_EQ(0, tex_params.level);
250 DCHECK_EQ(EGL_NO_IMAGE_KHR, egl_image_);
251
252 void* data =
253 AsyncPixelTransferDelegate::GetAddress(safe_shared_memory, mem_params);
254 {
255 TRACE_EVENT0("gpu", "glTexImage2D no data");
256 glGenTextures(1, &thread_texture_id_);
257 glActiveTexture(GL_TEXTURE0);
258 glBindTexture(GL_TEXTURE_2D, thread_texture_id_);
259
260 SetGlParametersForEglImageTexture();
261
262 // If we need to use image_preserved, we pass the data with
263 // the allocation. Otherwise we use a NULL allocation to
264 // try to avoid any costs associated with creating the EGLImage.
265 if (use_image_preserved_)
266 DoTexImage2D(tex_params, data);
267 else
268 DoTexImage2D(tex_params, NULL);
269 }
270
271 CreateEglImageOnUploadThread();
272
273 {
274 TRACE_EVENT0("gpu", "glTexSubImage2D with data");
275
276 // If we didn't use image_preserved, we haven't uploaded
277 // the data yet, so we do this with a full texSubImage.
278 if (!use_image_preserved_)
279 DoFullTexSubImage2D(tex_params, data);
280 }
281
282 WaitForLastUpload();
283 MarkAsCompleted();
284
285 DCHECK(CHECK_GL());
286 }
287
288 void PerformAsyncTexSubImage2D(
289 AsyncTexSubImage2DParams tex_params,
290 AsyncMemoryParams mem_params,
291 ScopedSafeSharedMemory* safe_shared_memory,
292 scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) {
293 TRACE_EVENT2("gpu",
294 "PerformAsyncTexSubImage2D",
295 "width",
296 tex_params.width,
297 "height",
298 tex_params.height);
299
300 DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_);
301 DCHECK_EQ(0, tex_params.level);
302
303 void* data =
304 AsyncPixelTransferDelegate::GetAddress(safe_shared_memory, mem_params);
305
306 base::TimeTicks begin_time;
307 if (texture_upload_stats)
308 begin_time = base::TimeTicks::HighResNow();
309
310 if (!thread_texture_id_) {
311 TRACE_EVENT0("gpu", "glEGLImageTargetTexture2DOES");
312 glGenTextures(1, &thread_texture_id_);
313 glActiveTexture(GL_TEXTURE0);
314 glBindTexture(GL_TEXTURE_2D, thread_texture_id_);
315 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_);
316 } else {
317 glActiveTexture(GL_TEXTURE0);
318 glBindTexture(GL_TEXTURE_2D, thread_texture_id_);
319 }
320 {
321 TRACE_EVENT0("gpu", "glTexSubImage2D");
322 DoTexSubImage2D(tex_params, data);
323 }
324 WaitForLastUpload();
325 MarkAsCompleted();
326
327 DCHECK(CHECK_GL());
328 if (texture_upload_stats) {
329 texture_upload_stats->AddUpload(base::TimeTicks::HighResNow() -
330 begin_time);
331 }
332 }
333
334 protected:
335 friend class base::RefCountedThreadSafe<TransferStateInternal>;
336 friend class gpu::AsyncPixelTransferDelegateEGL;
337
338 static void DeleteTexture(GLuint id) {
339 glDeleteTextures(1, &id);
340 }
341
342 virtual ~TransferStateInternal() {
343 if (egl_image_ != EGL_NO_IMAGE_KHR) {
344 EGLDisplay display = eglGetCurrentDisplay();
345 eglDestroyImageKHR(display, egl_image_);
346 }
347 if (thread_texture_id_) {
348 transfer_message_loop_proxy()->PostTask(FROM_HERE,
349 base::Bind(&DeleteTexture, thread_texture_id_));
350 }
351 }
352
353 // The 'real' texture.
354 GLuint texture_id_;
355
356 // The EGLImage sibling on the upload thread.
357 GLuint thread_texture_id_;
358
359 // Definition params for texture that needs binding.
360 AsyncTexImage2DParams define_params_;
361
362 // Indicates that an async transfer is in progress.
363 base::WaitableEvent transfer_completion_;
364
365 // It would be nice if we could just create a new EGLImage for
366 // every upload, but I found that didn't work, so this stores
367 // one for the lifetime of the texture.
368 EGLImageKHR egl_image_;
369
370 // Callback to invoke when AsyncTexImage2D is complete
371 // and the client can safely use the texture. This occurs
372 // during BindCompletedAsyncTransfers().
373 base::Closure bind_callback_;
374
375 // Customize when we block on fences (these are work-arounds).
376 bool wait_for_uploads_;
377 bool wait_for_creation_;
378 bool use_image_preserved_;
379 };
380
381 // EGL needs thread-safe ref-counting, so this just wraps
382 // an internal thread-safe ref-counted state object.
383 class AsyncTransferStateImpl : public AsyncPixelTransferState {
384 public:
385 AsyncTransferStateImpl(GLuint texture_id,
386 const AsyncTexImage2DParams& define_params,
387 bool wait_for_uploads,
388 bool wait_for_creation,
389 bool use_image_preserved)
390 : internal_(new TransferStateInternal(texture_id,
391 define_params,
392 wait_for_uploads,
393 wait_for_creation,
394 use_image_preserved)) {
395 }
396
397 virtual bool TransferIsInProgress() OVERRIDE {
398 return internal_->TransferIsInProgress();
399 }
400
401 void BindTransfer() {
402 internal_->BindTransfer();
403 }
404
405 scoped_refptr<TransferStateInternal> internal_;
406
407 private:
408 virtual ~AsyncTransferStateImpl() {}
409 };
410
411 } // namespace
412
413 AsyncPixelTransferDelegateEGL::AsyncPixelTransferDelegateEGL() {
414 std::string vendor;
415 vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
416 is_imagination_ = vendor.find("Imagination") != std::string::npos;
417 is_qualcomm_ = vendor.find("Qualcomm") != std::string::npos;
418 // TODO(reveman): Skip this if --enable-gpu-benchmarking is not present.
419 texture_upload_stats_ = make_scoped_refptr(new AsyncPixelTransferUploadStats);
420 }
421
422 AsyncPixelTransferDelegateEGL::~AsyncPixelTransferDelegateEGL() {}
423
424 AsyncPixelTransferState* AsyncPixelTransferDelegateEGL::
425 CreatePixelTransferState(GLuint texture_id,
426 const AsyncTexImage2DParams& define_params) {
427 // We can't wait on uploads on imagination (it can take 200ms+).
428 // In practice, they are complete when the CPU glTexSubImage2D completes.
429 bool wait_for_uploads = !is_imagination_;
430
431 // Qualcomm runs into texture corruption problems if the same texture is
432 // uploaded to with both async and normal uploads. Synchronize after EGLImage
433 // creation on the main thread as a work-around.
434 bool wait_for_creation = is_qualcomm_;
435
436 // Qualcomm has a race when using image_preserved=FALSE,
437 // which can result in black textures even after the first upload.
438 // Since using FALSE is mainly for performance (to avoid layout changes),
439 // but Qualcomm itself doesn't seem to get any performance benefit,
440 // we just using image_preservedd=TRUE on Qualcomm as a work-around.
441 bool use_image_preserved = is_qualcomm_ || is_imagination_;
442
443 return new AsyncTransferStateImpl(texture_id,
444 define_params,
445 wait_for_uploads,
446 wait_for_creation,
447 use_image_preserved);
448 }
449
450 void AsyncPixelTransferDelegateEGL::BindCompletedAsyncTransfers() {
451 scoped_ptr<gfx::ScopedTextureBinder> texture_binder;
452
453 while(!pending_allocations_.empty()) {
454 if (!pending_allocations_.front().get()) {
455 pending_allocations_.pop_front();
456 continue;
457 }
458 scoped_refptr<TransferStateInternal> state =
459 static_cast<AsyncTransferStateImpl*>
460 (pending_allocations_.front().get())->internal_.get();
461 // Terminate early, as all transfers finish in order, currently.
462 if (state->TransferIsInProgress())
463 break;
464
465 if (!texture_binder)
466 texture_binder.reset(new gfx::ScopedTextureBinder(GL_TEXTURE_2D, 0));
467
468 // If the transfer is finished, bind it to the texture
469 // and remove it from pending list.
470 state->BindTransfer();
471 pending_allocations_.pop_front();
472 }
473 }
474
475 void AsyncPixelTransferDelegateEGL::AsyncNotifyCompletion(
476 const AsyncMemoryParams& mem_params,
477 const CompletionCallback& callback) {
478 DCHECK(mem_params.shared_memory);
479 DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
480 mem_params.shm_size);
481 // Post a PerformNotifyCompletion task to the upload thread. This task
482 // will run after all async transfers are complete.
483 transfer_message_loop_proxy()->PostTask(
484 FROM_HERE,
485 base::Bind(&AsyncPixelTransferDelegateEGL::PerformNotifyCompletion,
486 mem_params,
487 base::Owned(
488 new ScopedSafeSharedMemory(safe_shared_memory_pool(),
489 mem_params.shared_memory,
490 mem_params.shm_size)),
491 callback));
492 }
493
494 void AsyncPixelTransferDelegateEGL::WaitForTransferCompletion(
495 AsyncPixelTransferState* transfer_state) {
496 scoped_refptr<TransferStateInternal> state =
497 static_cast<AsyncTransferStateImpl*>(transfer_state)->internal_.get();
498 DCHECK(state);
499 DCHECK(state->texture_id_);
500
501 if (state->TransferIsInProgress()) {
502 #if defined(OS_ANDROID) || defined(OS_LINUX)
503 g_transfer_thread.Pointer()->SetPriority(base::kThreadPriority_Display);
504 #endif
505
506 state->WaitForTransferCompletion();
507 DCHECK(!state->TransferIsInProgress());
508
509 #if defined(OS_ANDROID) || defined(OS_LINUX)
510 g_transfer_thread.Pointer()->SetPriority(base::kThreadPriority_Background);
511 #endif
512 }
513 }
514
515 void AsyncPixelTransferDelegateEGL::AsyncTexImage2D(
516 AsyncPixelTransferState* transfer_state,
517 const AsyncTexImage2DParams& tex_params,
518 const AsyncMemoryParams& mem_params,
519 const base::Closure& bind_callback) {
520 if (WorkAroundAsyncTexImage2D(transfer_state, tex_params,
521 mem_params, bind_callback))
522 return;
523
524 scoped_refptr<TransferStateInternal> state =
525 static_cast<AsyncTransferStateImpl*>(transfer_state)->internal_.get();
526 DCHECK(mem_params.shared_memory);
527 DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
528 mem_params.shm_size);
529 DCHECK(state);
530 DCHECK(state->texture_id_);
531 DCHECK(!state->TransferIsInProgress());
532 DCHECK_EQ(state->egl_image_, EGL_NO_IMAGE_KHR);
533 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
534 DCHECK_EQ(tex_params.level, 0);
535
536 // Mark the transfer in progress and save the late bind
537 // callback, so we can notify the client when it is bound.
538 pending_allocations_.push_back(transfer_state->AsWeakPtr());
539 state->bind_callback_ = bind_callback;
540
541 // Mark the transfer in progress.
542 state->MarkAsTransferIsInProgress();
543
544 // Duplicate the shared memory so there is no way we can get
545 // a use-after-free of the raw pixels.
546 transfer_message_loop_proxy()->PostTask(FROM_HERE,
547 base::Bind(
548 &TransferStateInternal::PerformAsyncTexImage2D,
549 state,
550 tex_params,
551 mem_params,
552 base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
553 mem_params.shared_memory,
554 mem_params.shm_size))));
555
556
557 DCHECK(CHECK_GL());
558 }
559
560 void AsyncPixelTransferDelegateEGL::AsyncTexSubImage2D(
561 AsyncPixelTransferState* transfer_state,
562 const AsyncTexSubImage2DParams& tex_params,
563 const AsyncMemoryParams& mem_params) {
564 TRACE_EVENT2("gpu", "AsyncTexSubImage2D",
565 "width", tex_params.width,
566 "height", tex_params.height);
567 if (WorkAroundAsyncTexSubImage2D(transfer_state, tex_params, mem_params))
568 return;
569 scoped_refptr<TransferStateInternal> state =
570 static_cast<AsyncTransferStateImpl*>(transfer_state)->internal_.get();
571
572 DCHECK(state->texture_id_);
573 DCHECK(!state->TransferIsInProgress());
574 DCHECK(mem_params.shared_memory);
575 DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
576 mem_params.shm_size);
577 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
578 DCHECK_EQ(tex_params.level, 0);
579
580 // Mark the transfer in progress.
581 state->MarkAsTransferIsInProgress();
582
583 // If this wasn't async allocated, we don't have an EGLImage yet.
584 // Create the EGLImage if it hasn't already been created.
585 state->CreateEglImageOnMainThreadIfNeeded();
586
587 // Duplicate the shared memory so there are no way we can get
588 // a use-after-free of the raw pixels.
589 transfer_message_loop_proxy()->PostTask(FROM_HERE,
590 base::Bind(
591 &TransferStateInternal::PerformAsyncTexSubImage2D,
592 state,
593 tex_params,
594 mem_params,
595 base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
596 mem_params.shared_memory,
597 mem_params.shm_size)),
598 texture_upload_stats_));
599
600 DCHECK(CHECK_GL());
601 }
602
603 uint32 AsyncPixelTransferDelegateEGL::GetTextureUploadCount() {
604 CHECK(texture_upload_stats_);
605 return texture_upload_stats_->GetStats(NULL);
606 }
607
608 base::TimeDelta AsyncPixelTransferDelegateEGL::GetTotalTextureUploadTime() {
609 CHECK(texture_upload_stats_);
610 base::TimeDelta total_texture_upload_time;
611 texture_upload_stats_->GetStats(&total_texture_upload_time);
612 return total_texture_upload_time;
613 }
614
615 void AsyncPixelTransferDelegateEGL::ProcessMorePendingTransfers() {
616 }
617
618 bool AsyncPixelTransferDelegateEGL::NeedsProcessMorePendingTransfers() {
619 return false;
620 }
621
622 void AsyncPixelTransferDelegateEGL::PerformNotifyCompletion(
623 AsyncMemoryParams mem_params,
624 ScopedSafeSharedMemory* safe_shared_memory,
625 const CompletionCallback& callback) {
626 TRACE_EVENT0("gpu", "PerformNotifyCompletion");
627 AsyncMemoryParams safe_mem_params = mem_params;
628 safe_mem_params.shared_memory = safe_shared_memory->shared_memory();
629 callback.Run(safe_mem_params);
630 }
631
632 namespace {
633 bool IsPowerOfTwo (unsigned int x) {
634 return ((x != 0) && !(x & (x - 1)));
635 }
636
637 bool IsMultipleOfEight(unsigned int x) {
638 return (x & 7) == 0;
639 }
640
641 bool DimensionsSupportImgFastPath(int width, int height) {
642 // Multiple of eight, but not a power of two.
643 return IsMultipleOfEight(width) &&
644 IsMultipleOfEight(height) &&
645 !(IsPowerOfTwo(width) &&
646 IsPowerOfTwo(height));
647 }
648 } // namespace
649
650 // It is very difficult to stream uploads on Imagination GPUs:
651 // - glTexImage2D defers a swizzle/stall until draw-time
652 // - glTexSubImage2D will sleep for 16ms on a good day, and 100ms
653 // or longer if OpenGL is in heavy use by another thread.
654 // The one combination that avoids these problems requires:
655 // a.) Allocations/Uploads must occur on different threads/contexts.
656 // b.) Texture size must be non-power-of-two.
657 // When using a+b, uploads will be incorrect/corrupt unless:
658 // c.) Texture size must be a multiple-of-eight.
659 //
660 // To achieve a.) we allocate synchronously on the main thread followed
661 // by uploading on the upload thread. When b/c are not true we fall back
662 // on purely synchronous allocation/upload on the main thread.
663
664 bool AsyncPixelTransferDelegateEGL::WorkAroundAsyncTexImage2D(
665 AsyncPixelTransferState* transfer_state,
666 const AsyncTexImage2DParams& tex_params,
667 const AsyncMemoryParams& mem_params,
668 const base::Closure& bind_callback) {
669 if (!is_imagination_)
670 return false;
671 scoped_refptr<TransferStateInternal> state =
672 static_cast<AsyncTransferStateImpl*>(transfer_state)->internal_.get();
673
674 // On imagination we allocate synchronously all the time, even
675 // if the dimensions support fast uploads. This is for part a.)
676 // above, so allocations occur on a different thread/context as uploads.
677 void* data = GetAddress(mem_params);
678 SetGlParametersForEglImageTexture();
679
680 {
681 TRACE_EVENT0("gpu", "glTexImage2D with data");
682 DoTexImage2D(tex_params, data);
683 }
684
685 // The allocation has already occured, so mark it as finished
686 // and ready for binding.
687 CHECK(!state->TransferIsInProgress());
688
689 // If the dimensions support fast async uploads, create the
690 // EGLImage for future uploads. The late bind should not
691 // be needed since the EGLImage was created from the main thread
692 // texture, but this is required to prevent an imagination driver crash.
693 if (DimensionsSupportImgFastPath(tex_params.width, tex_params.height)) {
694 state->CreateEglImageOnMainThreadIfNeeded();
695 pending_allocations_.push_back(transfer_state->AsWeakPtr());
696 state->bind_callback_ = bind_callback;
697 }
698
699 DCHECK(CHECK_GL());
700 return true;
701 }
702
703 bool AsyncPixelTransferDelegateEGL::WorkAroundAsyncTexSubImage2D(
704 AsyncPixelTransferState* transfer_state,
705 const AsyncTexSubImage2DParams& tex_params,
706 const AsyncMemoryParams& mem_params) {
707 if (!is_imagination_)
708 return false;
709
710 // If the dimensions support fast async uploads, we can use the
711 // normal async upload path for uploads.
712 if (DimensionsSupportImgFastPath(tex_params.width, tex_params.height))
713 return false;
714
715 scoped_refptr<TransferStateInternal> state =
716 static_cast<AsyncTransferStateImpl*>(transfer_state)->internal_.get();
717
718 // Fall back on a synchronous stub as we don't have a known fast path.
719 // Also, older ICS drivers crash when we do any glTexSubImage2D on the
720 // same thread. To work around this we do glTexImage2D instead. Since
721 // we didn't create an EGLImage for this texture (see above), this is
722 // okay, but it limits this API to full updates for now.
723 DCHECK(!state->egl_image_);
724 DCHECK_EQ(tex_params.xoffset, 0);
725 DCHECK_EQ(tex_params.yoffset, 0);
726 DCHECK_EQ(state->define_params_.width, tex_params.width);
727 DCHECK_EQ(state->define_params_.height, tex_params.height);
728 DCHECK_EQ(state->define_params_.level, tex_params.level);
729 DCHECK_EQ(state->define_params_.format, tex_params.format);
730 DCHECK_EQ(state->define_params_.type, tex_params.type);
731
732 void* data = GetAddress(mem_params);
733 base::TimeTicks begin_time;
734 if (texture_upload_stats_)
735 begin_time = base::TimeTicks::HighResNow();
736 {
737 TRACE_EVENT0("gpu", "glTexSubImage2D");
738 // Note we use define_params_ instead of tex_params.
739 // The DCHECKs above verify this is always the same.
740 DoTexImage2D(state->define_params_, data);
741 }
742 if (texture_upload_stats_) {
743 texture_upload_stats_->AddUpload(
744 base::TimeTicks::HighResNow() - begin_time);
745 }
746
747 DCHECK(CHECK_GL());
748 return true;
749 }
750
751 } // namespace gpu
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698