Home | History | Annotate | Download | only in service
      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_idle.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/debug/trace_event.h"
      9 #include "base/debug/trace_event_synthetic_delay.h"
     10 #include "base/lazy_instance.h"
     11 #include "base/memory/weak_ptr.h"
     12 #include "ui/gl/scoped_binders.h"
     13 
     14 namespace gpu {
     15 
     16 namespace {
     17 
     18 static uint64 g_next_pixel_transfer_state_id = 1;
     19 
     20 void PerformNotifyCompletion(
     21     AsyncMemoryParams mem_params,
     22     scoped_refptr<AsyncPixelTransferCompletionObserver> observer) {
     23   TRACE_EVENT0("gpu", "PerformNotifyCompletion");
     24   observer->DidComplete(mem_params);
     25 }
     26 
     27 }  // namespace
     28 
     29 // Class which handles async pixel transfers in a platform
     30 // independent way.
     31 class AsyncPixelTransferDelegateIdle
     32     : public AsyncPixelTransferDelegate,
     33       public base::SupportsWeakPtr<AsyncPixelTransferDelegateIdle> {
     34  public:
     35   AsyncPixelTransferDelegateIdle(
     36       AsyncPixelTransferManagerIdle::SharedState* state,
     37       GLuint texture_id,
     38       const AsyncTexImage2DParams& define_params);
     39   virtual ~AsyncPixelTransferDelegateIdle();
     40 
     41   // Implement AsyncPixelTransferDelegate:
     42   virtual void AsyncTexImage2D(
     43       const AsyncTexImage2DParams& tex_params,
     44       const AsyncMemoryParams& mem_params,
     45       const base::Closure& bind_callback) OVERRIDE;
     46   virtual void AsyncTexSubImage2D(
     47       const AsyncTexSubImage2DParams& tex_params,
     48       const AsyncMemoryParams& mem_params) OVERRIDE;
     49   virtual bool TransferIsInProgress() OVERRIDE;
     50   virtual void WaitForTransferCompletion() OVERRIDE;
     51 
     52  private:
     53   void PerformAsyncTexImage2D(AsyncTexImage2DParams tex_params,
     54                               AsyncMemoryParams mem_params,
     55                               const base::Closure& bind_callback);
     56   void PerformAsyncTexSubImage2D(AsyncTexSubImage2DParams tex_params,
     57                                  AsyncMemoryParams mem_params);
     58 
     59   uint64 id_;
     60   GLuint texture_id_;
     61   bool transfer_in_progress_;
     62   AsyncTexImage2DParams define_params_;
     63 
     64   // Safe to hold a raw pointer because SharedState is owned by the Manager
     65   // which owns the Delegate.
     66   AsyncPixelTransferManagerIdle::SharedState* shared_state_;
     67 
     68   DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateIdle);
     69 };
     70 
     71 AsyncPixelTransferDelegateIdle::AsyncPixelTransferDelegateIdle(
     72     AsyncPixelTransferManagerIdle::SharedState* shared_state,
     73     GLuint texture_id,
     74     const AsyncTexImage2DParams& define_params)
     75     : id_(g_next_pixel_transfer_state_id++),
     76       texture_id_(texture_id),
     77       transfer_in_progress_(false),
     78       define_params_(define_params),
     79       shared_state_(shared_state) {}
     80 
     81 AsyncPixelTransferDelegateIdle::~AsyncPixelTransferDelegateIdle() {}
     82 
     83 void AsyncPixelTransferDelegateIdle::AsyncTexImage2D(
     84     const AsyncTexImage2DParams& tex_params,
     85     const AsyncMemoryParams& mem_params,
     86     const base::Closure& bind_callback) {
     87   TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("gpu.AsyncTexImage");
     88   DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
     89 
     90   shared_state_->tasks.push_back(AsyncPixelTransferManagerIdle::Task(
     91       id_,
     92       this,
     93       base::Bind(&AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D,
     94                  AsWeakPtr(),
     95                  tex_params,
     96                  mem_params,
     97                  bind_callback)));
     98 
     99   transfer_in_progress_ = true;
    100 }
    101 
    102 void AsyncPixelTransferDelegateIdle::AsyncTexSubImage2D(
    103     const AsyncTexSubImage2DParams& tex_params,
    104     const AsyncMemoryParams& mem_params) {
    105   TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("gpu.AsyncTexImage");
    106   DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
    107 
    108   shared_state_->tasks.push_back(AsyncPixelTransferManagerIdle::Task(
    109       id_,
    110       this,
    111       base::Bind(&AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D,
    112                  AsWeakPtr(),
    113                  tex_params,
    114                  mem_params)));
    115 
    116   transfer_in_progress_ = true;
    117 }
    118 
    119 bool  AsyncPixelTransferDelegateIdle::TransferIsInProgress() {
    120   return transfer_in_progress_;
    121 }
    122 
    123 void AsyncPixelTransferDelegateIdle::WaitForTransferCompletion() {
    124   for (std::list<AsyncPixelTransferManagerIdle::Task>::iterator iter =
    125            shared_state_->tasks.begin();
    126        iter != shared_state_->tasks.end();
    127        ++iter) {
    128     if (iter->transfer_id != id_)
    129       continue;
    130 
    131     (*iter).task.Run();
    132     shared_state_->tasks.erase(iter);
    133     break;
    134   }
    135 
    136   shared_state_->ProcessNotificationTasks();
    137 }
    138 
    139 void AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D(
    140     AsyncTexImage2DParams tex_params,
    141     AsyncMemoryParams mem_params,
    142     const base::Closure& bind_callback) {
    143   TRACE_EVENT2("gpu", "PerformAsyncTexImage2D",
    144                "width", tex_params.width,
    145                "height", tex_params.height);
    146 
    147   void* data = mem_params.GetDataAddress();
    148 
    149   base::TimeTicks begin_time(base::TimeTicks::HighResNow());
    150   gfx::ScopedTextureBinder texture_binder(tex_params.target, texture_id_);
    151 
    152   {
    153     TRACE_EVENT0("gpu", "glTexImage2D");
    154     glTexImage2D(
    155         tex_params.target,
    156         tex_params.level,
    157         tex_params.internal_format,
    158         tex_params.width,
    159         tex_params.height,
    160         tex_params.border,
    161         tex_params.format,
    162         tex_params.type,
    163         data);
    164   }
    165 
    166   TRACE_EVENT_SYNTHETIC_DELAY_END("gpu.AsyncTexImage");
    167   transfer_in_progress_ = false;
    168   shared_state_->texture_upload_count++;
    169   shared_state_->total_texture_upload_time +=
    170       base::TimeTicks::HighResNow() - begin_time;
    171 
    172   // The texture is already fully bound so just call it now.
    173   bind_callback.Run();
    174 }
    175 
    176 void AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D(
    177     AsyncTexSubImage2DParams tex_params,
    178     AsyncMemoryParams mem_params) {
    179   TRACE_EVENT2("gpu", "PerformAsyncTexSubImage2D",
    180                "width", tex_params.width,
    181                "height", tex_params.height);
    182 
    183   void* data = mem_params.GetDataAddress();
    184 
    185   base::TimeTicks begin_time(base::TimeTicks::HighResNow());
    186   gfx::ScopedTextureBinder texture_binder(tex_params.target, texture_id_);
    187 
    188   // If it's a full texture update, use glTexImage2D as it's faster.
    189   // TODO(epenner): Make this configurable (http://crbug.com/259924)
    190   if (tex_params.xoffset == 0 &&
    191       tex_params.yoffset == 0 &&
    192       tex_params.target == define_params_.target &&
    193       tex_params.level  == define_params_.level &&
    194       tex_params.width  == define_params_.width &&
    195       tex_params.height == define_params_.height) {
    196     TRACE_EVENT0("gpu", "glTexImage2D");
    197     glTexImage2D(
    198         define_params_.target,
    199         define_params_.level,
    200         define_params_.internal_format,
    201         define_params_.width,
    202         define_params_.height,
    203         define_params_.border,
    204         tex_params.format,
    205         tex_params.type,
    206         data);
    207   } else {
    208     TRACE_EVENT0("gpu", "glTexSubImage2D");
    209     glTexSubImage2D(
    210         tex_params.target,
    211         tex_params.level,
    212         tex_params.xoffset,
    213         tex_params.yoffset,
    214         tex_params.width,
    215         tex_params.height,
    216         tex_params.format,
    217         tex_params.type,
    218         data);
    219   }
    220 
    221   TRACE_EVENT_SYNTHETIC_DELAY_END("gpu.AsyncTexImage");
    222   transfer_in_progress_ = false;
    223   shared_state_->texture_upload_count++;
    224   shared_state_->total_texture_upload_time +=
    225       base::TimeTicks::HighResNow() - begin_time;
    226 }
    227 
    228 AsyncPixelTransferManagerIdle::Task::Task(
    229     uint64 transfer_id,
    230     AsyncPixelTransferDelegate* delegate,
    231     const base::Closure& task)
    232     : transfer_id(transfer_id),
    233       delegate(delegate),
    234       task(task) {
    235 }
    236 
    237 AsyncPixelTransferManagerIdle::Task::~Task() {}
    238 
    239 AsyncPixelTransferManagerIdle::SharedState::SharedState()
    240     : texture_upload_count(0) {}
    241 
    242 AsyncPixelTransferManagerIdle::SharedState::~SharedState() {}
    243 
    244 void AsyncPixelTransferManagerIdle::SharedState::ProcessNotificationTasks() {
    245   while (!tasks.empty()) {
    246     // Stop when we reach a pixel transfer task.
    247     if (tasks.front().transfer_id)
    248       return;
    249 
    250     tasks.front().task.Run();
    251     tasks.pop_front();
    252   }
    253 }
    254 
    255 AsyncPixelTransferManagerIdle::AsyncPixelTransferManagerIdle()
    256   : shared_state_() {
    257 }
    258 
    259 AsyncPixelTransferManagerIdle::~AsyncPixelTransferManagerIdle() {}
    260 
    261 void AsyncPixelTransferManagerIdle::BindCompletedAsyncTransfers() {
    262   // Everything is already bound.
    263 }
    264 
    265 void AsyncPixelTransferManagerIdle::AsyncNotifyCompletion(
    266     const AsyncMemoryParams& mem_params,
    267     AsyncPixelTransferCompletionObserver* observer) {
    268   if (shared_state_.tasks.empty()) {
    269     observer->DidComplete(mem_params);
    270     return;
    271   }
    272 
    273   shared_state_.tasks.push_back(
    274       Task(0,  // 0 transfer_id for notification tasks.
    275            NULL,
    276            base::Bind(
    277                &PerformNotifyCompletion,
    278                mem_params,
    279                make_scoped_refptr(observer))));
    280 }
    281 
    282 uint32 AsyncPixelTransferManagerIdle::GetTextureUploadCount() {
    283   return shared_state_.texture_upload_count;
    284 }
    285 
    286 base::TimeDelta AsyncPixelTransferManagerIdle::GetTotalTextureUploadTime() {
    287   return shared_state_.total_texture_upload_time;
    288 }
    289 
    290 void AsyncPixelTransferManagerIdle::ProcessMorePendingTransfers() {
    291   if (shared_state_.tasks.empty())
    292     return;
    293 
    294   // First task should always be a pixel transfer task.
    295   DCHECK(shared_state_.tasks.front().transfer_id);
    296   shared_state_.tasks.front().task.Run();
    297   shared_state_.tasks.pop_front();
    298 
    299   shared_state_.ProcessNotificationTasks();
    300 }
    301 
    302 bool AsyncPixelTransferManagerIdle::NeedsProcessMorePendingTransfers() {
    303   return !shared_state_.tasks.empty();
    304 }
    305 
    306 void AsyncPixelTransferManagerIdle::WaitAllAsyncTexImage2D() {
    307   if (shared_state_.tasks.empty())
    308     return;
    309 
    310   const Task& task = shared_state_.tasks.back();
    311   if (task.delegate)
    312     task.delegate->WaitForTransferCompletion();
    313 }
    314 
    315 AsyncPixelTransferDelegate*
    316 AsyncPixelTransferManagerIdle::CreatePixelTransferDelegateImpl(
    317     gles2::TextureRef* ref,
    318     const AsyncTexImage2DParams& define_params) {
    319   return new AsyncPixelTransferDelegateIdle(&shared_state_,
    320                                             ref->service_id(),
    321                                             define_params);
    322 }
    323 
    324 }  // namespace gpu
    325