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

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

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

Powered by Google App Engine
This is Rietveld 408576698