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