Chromium Code Reviews| Index: ui/gl/async_pixel_transfer_delegate_android.cc |
| diff --git a/ui/gl/async_pixel_transfer_delegate_android.cc b/ui/gl/async_pixel_transfer_delegate_android.cc |
| index 68c329f162ab4df9febe1f351f73ba2e492a8f55..3185b44c0055ea84c99f2829a87844824d638a0a 100644 |
| --- a/ui/gl/async_pixel_transfer_delegate_android.cc |
| +++ b/ui/gl/async_pixel_transfer_delegate_android.cc |
| @@ -15,6 +15,7 @@ |
| #include "base/shared_memory.h" |
| #include "base/threading/thread.h" |
| #include "build/build_config.h" |
| +#include "gpu/command_buffer/common/gles2_cmd_format.h" |
| #include "ui/gl/async_pixel_transfer_delegate.h" |
| #include "ui/gl/async_pixel_transfer_delegate_stub.h" |
| #include "ui/gl/egl_util.h" |
| @@ -32,6 +33,34 @@ namespace gfx { |
| namespace { |
| +class TextureUploadStats |
|
epenner
2013/02/07 20:36:34
Can this be another change? I don't understand how
reveman
2013/02/07 21:30:52
I can't get rid of the replies and keep collecting
epenner
2013/02/07 21:59:47
I see, let's not get rid of the reply then? We sho
|
| + : public base::RefCountedThreadSafe<TextureUploadStats> { |
| + public: |
| + TextureUploadStats() : texture_upload_count_(0) {} |
| + |
| + void AddUpload(base::TimeDelta transfer_time) { |
| + base::AutoLock scoped_lock(lock_); |
| + texture_upload_count_++; |
| + total_texture_upload_time_ += transfer_time; |
| + } |
| + |
| + int GetStats(base::TimeDelta* total_texture_upload_time) { |
| + base::AutoLock scoped_lock(lock_); |
| + if (total_texture_upload_time) |
| + *total_texture_upload_time = total_texture_upload_time_; |
| + return texture_upload_count_; |
| + } |
| + |
| + private: |
| + friend class RefCountedThreadSafe<TextureUploadStats>; |
| + |
| + ~TextureUploadStats() {} |
| + |
| + int texture_upload_count_; |
| + base::TimeDelta total_texture_upload_time_; |
| + base::Lock lock_; |
| +}; |
| + |
| const char kAsyncTransferThreadName[] = "AsyncTransferThread"; |
| bool CheckErrors(const char* file, int line) { |
| @@ -152,6 +181,7 @@ class TransferStateInternal |
| // Implement AsyncPixelTransferState: |
| bool TransferIsInProgress() { |
| + base::AutoLock scoped_lock(transfer_in_progress_lock_); |
| return transfer_in_progress_; |
| } |
| @@ -233,6 +263,12 @@ class TransferStateInternal |
| } |
| } |
| + void MarkAsCompleted() { |
| + base::AutoLock scoped_lock(transfer_in_progress_lock_); |
| + DCHECK(transfer_in_progress_); |
| + transfer_in_progress_ = false; |
| + } |
| + |
| protected: |
| friend class base::RefCountedThreadSafe<TransferStateInternal>; |
| friend class AsyncPixelTransferDelegateAndroid; |
| @@ -267,15 +303,13 @@ class TransferStateInternal |
| // Indicates that an async transfer is in progress. |
| bool transfer_in_progress_; |
| + base::Lock transfer_in_progress_lock_; |
|
reveman
2013/02/07 19:59:02
we could use base::subtle::Atomic32 here instead i
epenner
2013/02/07 20:22:56
Can you explain a bit why we need a lock or atomic
reveman
2013/02/07 21:30:52
Both threads will access this. Main thread to dete
epenner
2013/02/07 21:59:47
That's what atomic ints are used for yes, but I'm
|
| // It would be nice if we could just create a new EGLImage for |
| // every upload, but I found that didn't work, so this stores |
| // one for the lifetime of the texture. |
| EGLImageKHR egl_image_; |
| - // Time spent performing last transfer. |
| - base::TimeDelta last_transfer_time_; |
| - |
| // Customize when we block on fences (these are work-arounds). |
| bool wait_for_uploads_; |
| bool wait_for_egl_images_; |
| @@ -304,16 +338,15 @@ class AsyncTransferStateAndroid : public AsyncPixelTransferState { |
| // Class which handles async pixel transfers on Android (using |
| // EGLImageKHR and another upload thread) |
| -class AsyncPixelTransferDelegateAndroid |
| - : public AsyncPixelTransferDelegate, |
| - public base::SupportsWeakPtr<AsyncPixelTransferDelegateAndroid> { |
| +class AsyncPixelTransferDelegateAndroid : public AsyncPixelTransferDelegate { |
| public: |
| AsyncPixelTransferDelegateAndroid(); |
| virtual ~AsyncPixelTransferDelegateAndroid(); |
| // implement AsyncPixelTransferDelegate: |
| virtual void AsyncNotifyCompletion( |
| - const base::Closure& task) OVERRIDE; |
| + const AsyncMemoryParams& mem_params, |
| + uint32 submit_count) OVERRIDE; |
| virtual void AsyncTexImage2D( |
| AsyncPixelTransferState* state, |
| const AsyncTexImage2DParams& tex_params, |
| @@ -330,9 +363,6 @@ class AsyncPixelTransferDelegateAndroid |
| virtual AsyncPixelTransferState* |
| CreateRawPixelTransferState(GLuint texture_id) OVERRIDE; |
| - void AsyncTexImage2DCompleted(scoped_refptr<TransferStateInternal> state); |
| - void AsyncTexSubImage2DCompleted(scoped_refptr<TransferStateInternal> state); |
| - |
| static void PerformAsyncTexImage2D( |
| TransferStateInternal* state, |
| AsyncTexImage2DParams tex_params, |
| @@ -342,7 +372,12 @@ class AsyncPixelTransferDelegateAndroid |
| TransferStateInternal* state, |
| AsyncTexSubImage2DParams tex_params, |
| base::SharedMemory* shared_memory, |
| - uint32 shared_memory_data_offset); |
| + uint32 shared_memory_data_offset, |
| + scoped_refptr<TextureUploadStats> texture_upload_stats); |
| + static void PerformNotifyCompletion( |
| + base::SharedMemory* shared_memory, |
| + uint32 shared_memory_data_offset, |
| + uint32 submit_count); |
| // Returns true if a work-around was used. |
| bool WorkAroundAsyncTexImage2D( |
| @@ -354,8 +389,7 @@ class AsyncPixelTransferDelegateAndroid |
| const AsyncTexSubImage2DParams& tex_params, |
| const AsyncMemoryParams& mem_params); |
| - int texture_upload_count_; |
| - base::TimeDelta total_texture_upload_time_; |
| + scoped_refptr<TextureUploadStats> texture_upload_stats_; |
| bool is_imagination_; |
| bool is_qualcomm_; |
| @@ -395,12 +429,13 @@ scoped_ptr<AsyncPixelTransferDelegate> |
| } |
| } |
| -AsyncPixelTransferDelegateAndroid::AsyncPixelTransferDelegateAndroid() |
| - : texture_upload_count_(0) { |
| +AsyncPixelTransferDelegateAndroid::AsyncPixelTransferDelegateAndroid() { |
| std::string vendor; |
| vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR)); |
| is_imagination_ = vendor.find("Imagination") != std::string::npos; |
| is_qualcomm_ = vendor.find("Qualcomm") != std::string::npos; |
| + // TODO(reveman): Skip this if --enable-gpu-benchmarking is not present. |
| + texture_upload_stats_ = make_scoped_refptr(new TextureUploadStats); |
| } |
| AsyncPixelTransferDelegateAndroid::~AsyncPixelTransferDelegateAndroid() { |
| @@ -422,19 +457,22 @@ AsyncPixelTransferState* |
| wait_for_egl_images)); |
| } |
| -namespace { |
| -// Dummy function to measure completion on |
| -// the upload thread. |
| -void NoOp() {} |
| -} // namespace |
| - |
| void AsyncPixelTransferDelegateAndroid::AsyncNotifyCompletion( |
| - const base::Closure& task) { |
| - // Post a no-op task to the upload thread followed |
| - // by a reply to the callback. The reply will then occur after |
| - // all async transfers are complete. |
| - transfer_message_loop_proxy()->PostTaskAndReply(FROM_HERE, |
| - base::Bind(&NoOp), task); |
| + const AsyncMemoryParams& mem_params, |
| + uint32 submit_count) { |
| + DCHECK(mem_params.shared_memory); |
| + DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size, |
| + mem_params.shm_size); |
| + // Post a PerformNotifyCompletion task to the upload thread. This task |
| + // will run after all async transfers are complete and mark the QuerySync as |
| + // completed. |
| + transfer_message_loop_proxy()->PostTask( |
| + FROM_HERE, |
| + base::Bind(&AsyncPixelTransferDelegateAndroid::PerformNotifyCompletion, |
| + base::Owned(DuplicateSharedMemory(mem_params.shared_memory, |
| + mem_params.shm_size)), |
| + mem_params.shm_data_offset, |
| + submit_count)); |
| } |
| void AsyncPixelTransferDelegateAndroid::AsyncTexImage2D( |
| @@ -458,23 +496,19 @@ void AsyncPixelTransferDelegateAndroid::AsyncTexImage2D( |
| return; |
| // Mark the transfer in progress and save define params for lazy binding. |
| + state->needs_late_bind_ = true; |
| state->transfer_in_progress_ = true; |
| state->late_bind_define_params_ = tex_params; |
| // Duplicate the shared memory so there are no way we can get |
| // a use-after-free of the raw pixels. |
| - transfer_message_loop_proxy()->PostTaskAndReply(FROM_HERE, |
| - base::Bind( |
| - &AsyncPixelTransferDelegateAndroid::PerformAsyncTexImage2D, |
| - base::Unretained(state.get()), // This is referenced in reply below. |
| - tex_params, |
| - base::Owned(DuplicateSharedMemory(mem_params.shared_memory, |
| - mem_params.shm_size)), |
| - mem_params.shm_data_offset), |
| - base::Bind( |
| - &AsyncPixelTransferDelegateAndroid::AsyncTexImage2DCompleted, |
| - AsWeakPtr(), |
| - state)); |
| + transfer_message_loop_proxy()->PostTask(FROM_HERE, |
| + base::Bind(&AsyncPixelTransferDelegateAndroid::PerformAsyncTexImage2D, |
| + state, |
| + tex_params, |
| + base::Owned(DuplicateSharedMemory(mem_params.shared_memory, |
| + mem_params.shm_size)), |
| + mem_params.shm_data_offset)); |
| DCHECK(CHECK_GL()); |
| } |
| @@ -508,41 +542,28 @@ void AsyncPixelTransferDelegateAndroid::AsyncTexSubImage2D( |
| // Duplicate the shared memory so there are no way we can get |
| // a use-after-free of the raw pixels. |
| - transfer_message_loop_proxy()->PostTaskAndReply(FROM_HERE, |
| - base::Bind( |
| - &AsyncPixelTransferDelegateAndroid::PerformAsyncTexSubImage2D, |
| - base::Unretained(state.get()), // This is referenced in reply below. |
| - tex_params, |
| - base::Owned(DuplicateSharedMemory(mem_params.shared_memory, |
| - mem_params.shm_size)), |
| - mem_params.shm_data_offset), |
| - base::Bind( |
| - &AsyncPixelTransferDelegateAndroid::AsyncTexSubImage2DCompleted, |
| - AsWeakPtr(), |
| - state)); |
| + transfer_message_loop_proxy()->PostTask(FROM_HERE, |
| + base::Bind(&AsyncPixelTransferDelegateAndroid::PerformAsyncTexSubImage2D, |
| + state, |
| + tex_params, |
| + base::Owned(DuplicateSharedMemory(mem_params.shared_memory, |
| + mem_params.shm_size)), |
| + mem_params.shm_data_offset, |
| + texture_upload_stats_)); |
| DCHECK(CHECK_GL()); |
| } |
| uint32 AsyncPixelTransferDelegateAndroid::GetTextureUploadCount() { |
| - return texture_upload_count_; |
| + CHECK(texture_upload_stats_); |
| + return texture_upload_stats_->GetStats(NULL); |
| } |
| base::TimeDelta AsyncPixelTransferDelegateAndroid::GetTotalTextureUploadTime() { |
| - return total_texture_upload_time_; |
| -} |
| - |
| -void AsyncPixelTransferDelegateAndroid::AsyncTexImage2DCompleted( |
| - scoped_refptr<TransferStateInternal> state) { |
| - state->needs_late_bind_ = true; |
| - state->transfer_in_progress_ = false; |
| -} |
| - |
| -void AsyncPixelTransferDelegateAndroid::AsyncTexSubImage2DCompleted( |
| - scoped_refptr<TransferStateInternal> state) { |
| - state->transfer_in_progress_ = false; |
| - texture_upload_count_++; |
| - total_texture_upload_time_ += state->last_transfer_time_; |
| + CHECK(texture_upload_stats_); |
| + base::TimeDelta total_texture_upload_time; |
| + texture_upload_stats_->GetStats(&total_texture_upload_time); |
| + return total_texture_upload_time; |
| } |
| namespace { |
| @@ -610,6 +631,8 @@ void AsyncPixelTransferDelegateAndroid::PerformAsyncTexImage2D( |
| } |
| state->WaitForLastUpload(); |
| + state->MarkAsCompleted(); |
| + |
| DCHECK(CHECK_GL()); |
| } |
| @@ -617,7 +640,8 @@ void AsyncPixelTransferDelegateAndroid::PerformAsyncTexSubImage2D( |
| TransferStateInternal* state, |
| AsyncTexSubImage2DParams tex_params, |
| base::SharedMemory* shared_memory, |
| - uint32 shared_memory_data_offset) { |
| + uint32 shared_memory_data_offset, |
| + scoped_refptr<TextureUploadStats> texture_upload_stats) { |
| TRACE_EVENT2("gpu", "PerformAsyncTexSubImage2D", |
| "width", tex_params.width, |
| "height", tex_params.height); |
| @@ -630,7 +654,10 @@ void AsyncPixelTransferDelegateAndroid::PerformAsyncTexSubImage2D( |
| void* data = GetAddress(shared_memory, shared_memory_data_offset); |
| - base::TimeTicks begin_time(base::TimeTicks::HighResNow()); |
| + base::TimeTicks begin_time; |
| + if (texture_upload_stats) |
| + begin_time = base::TimeTicks::HighResNow(); |
| + |
| if (!state->thread_texture_id_) { |
| TRACE_EVENT0("gpu", "glEGLImageTargetTexture2DOES"); |
| glGenTextures(1, &state->thread_texture_id_); |
| @@ -655,11 +682,28 @@ void AsyncPixelTransferDelegateAndroid::PerformAsyncTexSubImage2D( |
| data); |
| } |
| state->WaitForLastUpload(); |
| + state->MarkAsCompleted(); |
| DCHECK(CHECK_GL()); |
| - state->last_transfer_time_ = base::TimeTicks::HighResNow() - begin_time; |
| + |
| + if (texture_upload_stats) { |
| + texture_upload_stats->AddUpload( |
| + base::TimeTicks::HighResNow() - begin_time); |
| + } |
| } |
| +void AsyncPixelTransferDelegateAndroid::PerformNotifyCompletion( |
| + base::SharedMemory* shared_memory, |
| + uint32 shared_memory_data_offset, |
| + uint32 submit_count) { |
| + TRACE_EVENT0("gpu", "PerformNotifyCompletion"); |
| + |
| + gpu::gles2::QuerySync* sync = static_cast<gpu::gles2::QuerySync*>( |
| + GetAddress(shared_memory, shared_memory_data_offset)); |
| + if (!sync) |
| + return; |
| + sync->process_count = submit_count; |
| +} |
| namespace { |
| bool IsPowerOfTwo (unsigned int x) { |
| @@ -754,7 +798,9 @@ bool AsyncPixelTransferDelegateAndroid::WorkAroundAsyncTexSubImage2D( |
| // Fall back on a synchronous stub as we don't have a known fast path. |
| void* data = GetAddress(mem_params.shared_memory, |
| mem_params.shm_data_offset); |
| - base::TimeTicks begin_time(base::TimeTicks::HighResNow()); |
| + base::TimeTicks begin_time; |
| + if (texture_upload_stats_) |
| + begin_time = base::TimeTicks::HighResNow(); |
| { |
| TRACE_EVENT0("gpu", "glTexSubImage2D"); |
| glTexSubImage2D( |
| @@ -768,8 +814,10 @@ bool AsyncPixelTransferDelegateAndroid::WorkAroundAsyncTexSubImage2D( |
| tex_params.type, |
| data); |
| } |
| - texture_upload_count_++; |
| - total_texture_upload_time_ += base::TimeTicks::HighResNow() - begin_time; |
| + if (texture_upload_stats_) { |
| + texture_upload_stats_->AddUpload( |
| + base::TimeTicks::HighResNow() - begin_time); |
| + } |
| DCHECK(CHECK_GL()); |
| return true; |