| OLD | NEW |
| (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_idle.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/lazy_instance.h" | |
| 9 #include "base/memory/weak_ptr.h" | |
| 10 #include "base/trace_event/trace_event.h" | |
| 11 #include "base/trace_event/trace_event_synthetic_delay.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 typedef base::Callback<GLuint()> TextureIdCallback; | |
| 36 AsyncPixelTransferDelegateIdle( | |
| 37 AsyncPixelTransferManagerIdle::SharedState* state, | |
| 38 const TextureIdCallback& texture_id_callback, | |
| 39 const AsyncTexImage2DParams& define_params); | |
| 40 ~AsyncPixelTransferDelegateIdle() override; | |
| 41 | |
| 42 // Implement AsyncPixelTransferDelegate: | |
| 43 void AsyncTexImage2D(const AsyncTexImage2DParams& tex_params, | |
| 44 const AsyncMemoryParams& mem_params, | |
| 45 const base::Closure& bind_callback) override; | |
| 46 void AsyncTexSubImage2D(const AsyncTexSubImage2DParams& tex_params, | |
| 47 const AsyncMemoryParams& mem_params) override; | |
| 48 bool TransferIsInProgress() override; | |
| 49 void WaitForTransferCompletion() override; | |
| 50 | |
| 51 private: | |
| 52 void PerformAsyncTexImage2D(AsyncTexImage2DParams tex_params, | |
| 53 AsyncMemoryParams mem_params, | |
| 54 const base::Closure& bind_callback); | |
| 55 void PerformAsyncTexSubImage2D(AsyncTexSubImage2DParams tex_params, | |
| 56 AsyncMemoryParams mem_params); | |
| 57 | |
| 58 uint64 id_; | |
| 59 TextureIdCallback texture_id_callback_; | |
| 60 bool transfer_in_progress_; | |
| 61 AsyncTexImage2DParams define_params_; | |
| 62 | |
| 63 // Safe to hold a raw pointer because SharedState is owned by the Manager | |
| 64 // which owns the Delegate. | |
| 65 AsyncPixelTransferManagerIdle::SharedState* shared_state_; | |
| 66 | |
| 67 DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateIdle); | |
| 68 }; | |
| 69 | |
| 70 AsyncPixelTransferDelegateIdle::AsyncPixelTransferDelegateIdle( | |
| 71 AsyncPixelTransferManagerIdle::SharedState* shared_state, | |
| 72 const TextureIdCallback& texture_id_callback, | |
| 73 const AsyncTexImage2DParams& define_params) | |
| 74 : id_(g_next_pixel_transfer_state_id++), | |
| 75 texture_id_callback_(texture_id_callback), | |
| 76 transfer_in_progress_(false), | |
| 77 define_params_(define_params), | |
| 78 shared_state_(shared_state) {} | |
| 79 | |
| 80 AsyncPixelTransferDelegateIdle::~AsyncPixelTransferDelegateIdle() {} | |
| 81 | |
| 82 void AsyncPixelTransferDelegateIdle::AsyncTexImage2D( | |
| 83 const AsyncTexImage2DParams& tex_params, | |
| 84 const AsyncMemoryParams& mem_params, | |
| 85 const base::Closure& bind_callback) { | |
| 86 TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("gpu.AsyncTexImage"); | |
| 87 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target); | |
| 88 | |
| 89 shared_state_->tasks.push_back(AsyncPixelTransferManagerIdle::Task( | |
| 90 id_, | |
| 91 this, | |
| 92 base::Bind(&AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D, | |
| 93 AsWeakPtr(), | |
| 94 tex_params, | |
| 95 mem_params, | |
| 96 bind_callback))); | |
| 97 | |
| 98 transfer_in_progress_ = true; | |
| 99 } | |
| 100 | |
| 101 void AsyncPixelTransferDelegateIdle::AsyncTexSubImage2D( | |
| 102 const AsyncTexSubImage2DParams& tex_params, | |
| 103 const AsyncMemoryParams& mem_params) { | |
| 104 TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("gpu.AsyncTexImage"); | |
| 105 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target); | |
| 106 | |
| 107 shared_state_->tasks.push_back(AsyncPixelTransferManagerIdle::Task( | |
| 108 id_, | |
| 109 this, | |
| 110 base::Bind(&AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D, | |
| 111 AsWeakPtr(), | |
| 112 tex_params, | |
| 113 mem_params))); | |
| 114 | |
| 115 transfer_in_progress_ = true; | |
| 116 } | |
| 117 | |
| 118 bool AsyncPixelTransferDelegateIdle::TransferIsInProgress() { | |
| 119 return transfer_in_progress_; | |
| 120 } | |
| 121 | |
| 122 void AsyncPixelTransferDelegateIdle::WaitForTransferCompletion() { | |
| 123 for (std::list<AsyncPixelTransferManagerIdle::Task>::iterator iter = | |
| 124 shared_state_->tasks.begin(); | |
| 125 iter != shared_state_->tasks.end(); | |
| 126 ++iter) { | |
| 127 if (iter->transfer_id != id_) | |
| 128 continue; | |
| 129 | |
| 130 (*iter).task.Run(); | |
| 131 shared_state_->tasks.erase(iter); | |
| 132 break; | |
| 133 } | |
| 134 | |
| 135 shared_state_->ProcessNotificationTasks(); | |
| 136 } | |
| 137 | |
| 138 void AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D( | |
| 139 AsyncTexImage2DParams tex_params, | |
| 140 AsyncMemoryParams mem_params, | |
| 141 const base::Closure& bind_callback) { | |
| 142 TRACE_EVENT2("gpu", "PerformAsyncTexImage2D", | |
| 143 "width", tex_params.width, | |
| 144 "height", tex_params.height); | |
| 145 | |
| 146 void* data = mem_params.GetDataAddress(); | |
| 147 | |
| 148 base::TimeTicks begin_time(base::TimeTicks::Now()); | |
| 149 gfx::ScopedTextureBinder texture_binder(tex_params.target, | |
| 150 texture_id_callback_.Run()); | |
| 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::Now() - 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::Now()); | |
| 186 gfx::ScopedTextureBinder texture_binder(tex_params.target, | |
| 187 texture_id_callback_.Run()); | |
| 188 | |
| 189 if (shared_state_->use_teximage2d_over_texsubimage2d && | |
| 190 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::Now() - 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 bool use_teximage2d_over_texsubimage2d) | |
| 241 : use_teximage2d_over_texsubimage2d(use_teximage2d_over_texsubimage2d), | |
| 242 texture_upload_count(0) { | |
| 243 } | |
| 244 | |
| 245 AsyncPixelTransferManagerIdle::SharedState::~SharedState() {} | |
| 246 | |
| 247 void AsyncPixelTransferManagerIdle::SharedState::ProcessNotificationTasks() { | |
| 248 while (!tasks.empty()) { | |
| 249 // Stop when we reach a pixel transfer task. | |
| 250 if (tasks.front().transfer_id) | |
| 251 return; | |
| 252 | |
| 253 tasks.front().task.Run(); | |
| 254 tasks.pop_front(); | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 AsyncPixelTransferManagerIdle::AsyncPixelTransferManagerIdle( | |
| 259 bool use_teximage2d_over_texsubimage2d) | |
| 260 : shared_state_(use_teximage2d_over_texsubimage2d) { | |
| 261 } | |
| 262 | |
| 263 AsyncPixelTransferManagerIdle::~AsyncPixelTransferManagerIdle() {} | |
| 264 | |
| 265 void AsyncPixelTransferManagerIdle::BindCompletedAsyncTransfers() { | |
| 266 // Everything is already bound. | |
| 267 } | |
| 268 | |
| 269 void AsyncPixelTransferManagerIdle::AsyncNotifyCompletion( | |
| 270 const AsyncMemoryParams& mem_params, | |
| 271 AsyncPixelTransferCompletionObserver* observer) { | |
| 272 if (shared_state_.tasks.empty()) { | |
| 273 observer->DidComplete(mem_params); | |
| 274 return; | |
| 275 } | |
| 276 | |
| 277 shared_state_.tasks.push_back( | |
| 278 Task(0, // 0 transfer_id for notification tasks. | |
| 279 NULL, | |
| 280 base::Bind( | |
| 281 &PerformNotifyCompletion, | |
| 282 mem_params, | |
| 283 make_scoped_refptr(observer)))); | |
| 284 } | |
| 285 | |
| 286 uint32 AsyncPixelTransferManagerIdle::GetTextureUploadCount() { | |
| 287 return shared_state_.texture_upload_count; | |
| 288 } | |
| 289 | |
| 290 base::TimeDelta AsyncPixelTransferManagerIdle::GetTotalTextureUploadTime() { | |
| 291 return shared_state_.total_texture_upload_time; | |
| 292 } | |
| 293 | |
| 294 void AsyncPixelTransferManagerIdle::ProcessMorePendingTransfers() { | |
| 295 if (shared_state_.tasks.empty()) | |
| 296 return; | |
| 297 | |
| 298 // First task should always be a pixel transfer task. | |
| 299 DCHECK(shared_state_.tasks.front().transfer_id); | |
| 300 shared_state_.tasks.front().task.Run(); | |
| 301 shared_state_.tasks.pop_front(); | |
| 302 | |
| 303 shared_state_.ProcessNotificationTasks(); | |
| 304 } | |
| 305 | |
| 306 bool AsyncPixelTransferManagerIdle::NeedsProcessMorePendingTransfers() { | |
| 307 return !shared_state_.tasks.empty(); | |
| 308 } | |
| 309 | |
| 310 void AsyncPixelTransferManagerIdle::WaitAllAsyncTexImage2D() { | |
| 311 if (shared_state_.tasks.empty()) | |
| 312 return; | |
| 313 | |
| 314 const Task& task = shared_state_.tasks.back(); | |
| 315 if (task.delegate) | |
| 316 task.delegate->WaitForTransferCompletion(); | |
| 317 } | |
| 318 | |
| 319 AsyncPixelTransferDelegate* | |
| 320 AsyncPixelTransferManagerIdle::CreatePixelTransferDelegateImpl( | |
| 321 gles2::TextureRef* ref, | |
| 322 const AsyncTexImage2DParams& define_params) { | |
| 323 return new AsyncPixelTransferDelegateIdle( | |
| 324 &shared_state_, | |
| 325 // Not directly passing texture_ref->service_id here because it can change | |
| 326 // if avoid_egl_image_target_texture_reuse workaround is in effect. | |
| 327 // Unretained is safe because AsyncPixelTransferManager observes | |
| 328 // TextureRef destruction and destroys the delegate before TextureRef | |
| 329 // is destroyed. | |
| 330 base::Bind(&gles2::TextureRef::service_id, base::Unretained(ref)), | |
| 331 define_params); | |
| 332 } | |
| 333 | |
| 334 } // namespace gpu | |
| OLD | NEW |