Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gl/async_pixel_transfer_delegate_stub.h" | 5 #include "ui/gl/async_pixel_transfer_delegate_stub.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | |
| 8 #include "base/debug/trace_event.h" | |
| 9 #include "base/lazy_instance.h" | |
| 10 #include "base/message_loop.h" | |
| 11 #include "base/process_util.h" | |
| 7 #include "base/shared_memory.h" | 12 #include "base/shared_memory.h" |
| 8 #include "build/build_config.h" | 13 #include "build/build_config.h" |
| 9 #include "ui/gl/gl_bindings.h" | 14 #include "ui/gl/gl_bindings.h" |
| 15 #include "ui/gl/gl_context.h" | |
| 16 #include "ui/gl/gl_surface.h" | |
| 17 #include "ui/gl/safe_shared_memory_pool.h" | |
| 18 #include "ui/gl/scoped_make_current.h" | |
| 10 | 19 |
| 11 using base::SharedMemory; | 20 using base::SharedMemory; |
| 12 using base::SharedMemoryHandle; | 21 using base::SharedMemoryHandle; |
| 13 | 22 |
| 23 namespace gfx { | |
| 24 | |
| 14 namespace { | 25 namespace { |
| 26 | |
| 15 // Gets the address of the data from shared memory. | 27 // Gets the address of the data from shared memory. |
| 16 void* GetAddress(SharedMemory* shared_memory, | 28 void* GetAddress(SharedMemory* shared_memory, uint32 shm_data_offset) { |
| 17 uint32 shm_size, | |
| 18 uint32 shm_data_offset, | |
| 19 uint32 shm_data_size) { | |
| 20 // Memory bounds have already been validated, so there | 29 // Memory bounds have already been validated, so there |
| 21 // is just DCHECKS here. | 30 // is just DCHECKS here. |
| 22 DCHECK(shared_memory); | 31 DCHECK(shared_memory); |
| 23 DCHECK(shared_memory->memory()); | 32 DCHECK(shared_memory->memory()); |
| 24 DCHECK_LE(shm_data_offset + shm_data_size, shm_size); | |
| 25 return static_cast<int8*>(shared_memory->memory()) + shm_data_offset; | 33 return static_cast<int8*>(shared_memory->memory()) + shm_data_offset; |
| 26 } | 34 } |
| 35 | |
| 36 base::LazyInstance<SafeSharedMemoryPool> g_safe_shared_memory_pool = | |
| 37 LAZY_INSTANCE_INITIALIZER; | |
| 38 | |
| 39 SafeSharedMemoryPool* safe_shared_memory_pool() { | |
| 40 return g_safe_shared_memory_pool.Pointer(); | |
| 41 } | |
| 42 | |
| 27 } // namespace | 43 } // namespace |
| 28 | 44 |
| 29 namespace gfx { | |
| 30 | |
| 31 #if !defined(OS_ANDROID) | 45 #if !defined(OS_ANDROID) |
| 32 scoped_ptr<AsyncPixelTransferDelegate> | 46 scoped_ptr<AsyncPixelTransferDelegate> |
| 33 AsyncPixelTransferDelegate::Create(gfx::GLContext* context) { | 47 AsyncPixelTransferDelegate::Create(gfx::GLContext* context) { |
| 34 return AsyncPixelTransferDelegateStub::Create(context); | 48 return AsyncPixelTransferDelegateStub::Create(context); |
| 35 } | 49 } |
| 36 #endif | 50 #endif |
| 37 | 51 |
| 38 scoped_ptr<AsyncPixelTransferDelegate> | 52 scoped_ptr<AsyncPixelTransferDelegate> |
| 39 AsyncPixelTransferDelegateStub::Create(gfx::GLContext* context) { | 53 AsyncPixelTransferDelegateStub::Create(gfx::GLContext* context) { |
| 40 return make_scoped_ptr( | 54 return make_scoped_ptr( |
| 41 static_cast<AsyncPixelTransferDelegate*>( | 55 static_cast<AsyncPixelTransferDelegate*>( |
| 42 new AsyncPixelTransferDelegateStub())); | 56 new AsyncPixelTransferDelegateStub())); |
| 43 } | 57 } |
| 44 | 58 |
| 45 AsyncTransferStateStub::AsyncTransferStateStub(GLuint texture_id) { | 59 // Class which holds async pixel transfers state. |
| 46 static const AsyncTexImage2DParams zero_params = {0, 0, 0, 0, 0, 0, 0, 0}; | 60 class TransferStateInternalStub |
| 47 late_bind_define_params_ = zero_params; | 61 : public base::RefCounted<TransferStateInternalStub> { |
| 48 needs_late_bind_ = false; | 62 public: |
| 63 explicit TransferStateInternalStub(GLuint texture_id) | |
| 64 : texture_id_(texture_id), | |
| 65 needs_late_bind_(false), | |
| 66 transfer_in_progress_(false) { | |
| 67 static const AsyncTexImage2DParams zero_params = {0, 0, 0, 0, 0, 0, 0, 0}; | |
| 68 late_bind_define_params_ = zero_params; | |
| 69 } | |
| 70 | |
| 71 // Implement AsyncPixelTransferState: | |
| 72 bool TransferIsInProgress() { | |
| 73 return transfer_in_progress_; | |
| 74 } | |
| 75 | |
| 76 void BindTransfer(AsyncTexImage2DParams* bound_params) { | |
| 77 DCHECK(bound_params); | |
| 78 DCHECK(needs_late_bind_); | |
| 79 *bound_params = late_bind_define_params_; | |
| 80 needs_late_bind_ = false; | |
| 81 } | |
| 82 | |
| 83 protected: | |
| 84 friend class base::RefCounted<TransferStateInternalStub>; | |
| 85 friend class AsyncPixelTransferDelegateStub; | |
| 86 | |
| 87 virtual ~TransferStateInternalStub() {} | |
| 88 | |
| 89 GLuint texture_id_; | |
| 90 | |
| 91 // Indicates there is a new EGLImage and the 'real' | |
|
Sami
2013/03/07 16:57:19
No EGLImages here :)
reveman
2013/03/07 20:21:04
Done.
| |
| 92 // texture needs to be bound to it as an EGLImage target. | |
| 93 bool needs_late_bind_; | |
| 94 | |
| 95 // Definition params for texture that needs binding. | |
| 96 AsyncTexImage2DParams late_bind_define_params_; | |
| 97 | |
| 98 // Indicates that an async transfer is in progress. | |
| 99 bool transfer_in_progress_; | |
| 100 }; | |
| 101 | |
| 102 // This just wraps an internal ref-counted state object. | |
| 103 class AsyncTransferStateStub : public AsyncPixelTransferState { | |
| 104 public: | |
| 105 explicit AsyncTransferStateStub(GLuint texture_id) | |
| 106 : internal_(new TransferStateInternalStub(texture_id)) { | |
| 107 } | |
| 108 virtual ~AsyncTransferStateStub() {} | |
| 109 virtual bool TransferIsInProgress() { | |
| 110 return internal_->TransferIsInProgress(); | |
|
Sami
2013/03/07 16:57:19
Nit: indent by 2.
reveman
2013/03/07 20:21:04
Done.
| |
| 111 } | |
| 112 virtual void BindTransfer(AsyncTexImage2DParams* bound_params) { | |
| 113 internal_->BindTransfer(bound_params); | |
|
Sami
2013/03/07 16:57:19
Ditto.
reveman
2013/03/07 20:21:04
Done.
| |
| 114 } | |
| 115 scoped_refptr<TransferStateInternalStub> internal_; | |
| 116 }; | |
| 117 | |
| 118 AsyncPixelTransferDelegateStub::Transfer::Transfer( | |
| 119 TransferStateInternalStub* state, | |
| 120 const base::Closure& task) | |
| 121 : state(state), | |
| 122 task(task) { | |
| 49 } | 123 } |
| 50 | 124 |
| 51 AsyncTransferStateStub::~AsyncTransferStateStub() { | 125 AsyncPixelTransferDelegateStub::Transfer::~Transfer() {} |
| 52 } | |
| 53 | |
| 54 bool AsyncTransferStateStub::TransferIsInProgress() { | |
| 55 return false; | |
| 56 } | |
| 57 | |
| 58 void AsyncTransferStateStub::BindTransfer(AsyncTexImage2DParams* out_params) { | |
| 59 DCHECK(out_params); | |
| 60 DCHECK(needs_late_bind_); | |
| 61 *out_params = late_bind_define_params_; | |
| 62 needs_late_bind_ = false; | |
| 63 } | |
| 64 | 126 |
| 65 AsyncPixelTransferDelegateStub::AsyncPixelTransferDelegateStub() | 127 AsyncPixelTransferDelegateStub::AsyncPixelTransferDelegateStub() |
| 66 : texture_upload_count_(0) { | 128 : texture_upload_count_(0) { |
| 67 } | 129 } |
| 68 | 130 |
| 69 AsyncPixelTransferDelegateStub::~AsyncPixelTransferDelegateStub() { | 131 AsyncPixelTransferDelegateStub::~AsyncPixelTransferDelegateStub() { |
| 70 } | 132 } |
| 71 | 133 |
| 72 AsyncPixelTransferState* | 134 AsyncPixelTransferState* |
| 73 AsyncPixelTransferDelegateStub::CreateRawPixelTransferState( | 135 AsyncPixelTransferDelegateStub::CreateRawPixelTransferState( |
| 74 GLuint texture_id) { | 136 GLuint texture_id) { |
| 75 return static_cast<AsyncPixelTransferState*>( | 137 return static_cast<AsyncPixelTransferState*>( |
| 76 new AsyncTransferStateStub(texture_id)); | 138 new AsyncTransferStateStub(texture_id)); |
| 77 } | 139 } |
| 78 | 140 |
| 79 void AsyncPixelTransferDelegateStub::AsyncNotifyCompletion( | 141 void AsyncPixelTransferDelegateStub::AsyncNotifyCompletion( |
| 80 const AsyncMemoryParams& mem_params, | 142 const AsyncMemoryParams& mem_params, |
| 81 const CompletionCallback& callback) { | 143 const CompletionCallback& callback) { |
| 82 callback.Run(mem_params); | 144 if (transfers_.empty()) { |
| 145 callback.Run(mem_params); | |
| 146 return; | |
| 147 } | |
| 148 | |
| 149 transfers_.back().notifications.push( | |
| 150 base::Bind( | |
| 151 &AsyncPixelTransferDelegateStub::PerformNotifyCompletion, | |
| 152 AsWeakPtr(), | |
| 153 mem_params, | |
| 154 base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(), | |
| 155 mem_params.shared_memory, | |
| 156 mem_params.shm_size)), | |
| 157 callback)); | |
| 83 } | 158 } |
| 84 | 159 |
| 85 void AsyncPixelTransferDelegateStub::AsyncTexImage2D( | 160 void AsyncPixelTransferDelegateStub::AsyncTexImage2D( |
| 86 AsyncPixelTransferState* transfer_state, | 161 AsyncPixelTransferState* transfer_state, |
| 87 const AsyncTexImage2DParams& tex_params, | 162 const AsyncTexImage2DParams& tex_params, |
| 88 const AsyncMemoryParams& mem_params) { | 163 const AsyncMemoryParams& mem_params) { |
| 89 // Save the define params to return later during deferred | 164 scoped_refptr<TransferStateInternalStub> state = |
| 90 // binding of the transfer texture. | 165 static_cast<AsyncTransferStateStub*>(transfer_state)->internal_.get(); |
| 91 DCHECK(transfer_state); | 166 DCHECK(mem_params.shared_memory); |
| 92 AsyncTransferStateStub* state = | 167 DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size, |
| 93 static_cast<AsyncTransferStateStub*>(transfer_state); | 168 mem_params.shm_size); |
| 94 // We don't actually need a late bind since this stub does | 169 DCHECK(state); |
| 95 // everything synchronously, but this tries to be similar | 170 DCHECK(state->texture_id_); |
| 96 // as an async implementation. | 171 DCHECK(!state->needs_late_bind_); |
| 172 | |
| 173 // Mark the transfer in progress and save define params for lazy binding. | |
| 97 state->needs_late_bind_ = true; | 174 state->needs_late_bind_ = true; |
| 98 state->late_bind_define_params_ = tex_params; | 175 state->late_bind_define_params_ = tex_params; |
| 99 void* data = GetAddress(mem_params.shared_memory, | 176 |
| 100 mem_params.shm_size, | 177 transfers_.push_back( |
| 101 mem_params.shm_data_offset, | 178 Transfer( |
| 102 mem_params.shm_data_size); | 179 state.get(), |
| 103 glTexImage2D( | 180 base::Bind( |
| 104 tex_params.target, | 181 &AsyncPixelTransferDelegateStub::PerformAsyncTexImage2D, |
| 105 tex_params.level, | 182 AsWeakPtr(), |
| 106 tex_params.internal_format, | 183 state, |
| 107 tex_params.width, | 184 tex_params, |
| 108 tex_params.height, | 185 mem_params, |
| 109 tex_params.border, | 186 base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(), |
| 110 tex_params.format, | 187 mem_params.shared_memory, |
| 111 tex_params.type, | 188 mem_params.shm_size))))); |
| 112 data); | 189 |
| 190 state->transfer_in_progress_ = true; | |
| 113 } | 191 } |
| 114 | 192 |
| 115 void AsyncPixelTransferDelegateStub::AsyncTexSubImage2D( | 193 void AsyncPixelTransferDelegateStub::AsyncTexSubImage2D( |
| 116 AsyncPixelTransferState* transfer_state, | 194 AsyncPixelTransferState* transfer_state, |
| 117 const AsyncTexSubImage2DParams& tex_params, | 195 const AsyncTexSubImage2DParams& tex_params, |
| 118 const AsyncMemoryParams& mem_params) { | 196 const AsyncMemoryParams& mem_params) { |
| 119 void* data = GetAddress(mem_params.shared_memory, | 197 scoped_refptr<TransferStateInternalStub> state = |
| 120 mem_params.shm_size, | 198 static_cast<AsyncTransferStateStub*>(transfer_state)->internal_.get(); |
| 121 mem_params.shm_data_offset, | 199 DCHECK(mem_params.shared_memory); |
| 122 mem_params.shm_data_size); | 200 DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size, |
| 123 DCHECK(transfer_state); | 201 mem_params.shm_size); |
| 124 AsyncTransferStateStub* state = | 202 DCHECK(state); |
| 125 static_cast<AsyncTransferStateStub*>(transfer_state); | 203 DCHECK(state->texture_id_); |
| 126 DCHECK(!state->needs_late_bind_); | 204 DCHECK(!state->needs_late_bind_); |
| 127 base::TimeTicks begin_time(base::TimeTicks::HighResNow()); | 205 |
| 128 glTexSubImage2D( | 206 transfers_.push_back( |
| 129 tex_params.target, | 207 Transfer( |
| 130 tex_params.level, | 208 state.get(), |
| 131 tex_params.xoffset, | 209 base::Bind( |
| 132 tex_params.yoffset, | 210 &AsyncPixelTransferDelegateStub::PerformAsyncTexSubImage2D, |
| 133 tex_params.width, | 211 AsWeakPtr(), |
| 134 tex_params.height, | 212 state, |
| 135 tex_params.format, | 213 tex_params, |
| 136 tex_params.type, | 214 mem_params, |
| 137 data); | 215 base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(), |
| 138 texture_upload_count_++; | 216 mem_params.shared_memory, |
| 139 total_texture_upload_time_ += base::TimeTicks::HighResNow() - begin_time; | 217 mem_params.shm_size))))); |
| 218 | |
| 219 state->transfer_in_progress_ = true; | |
| 140 } | 220 } |
| 141 | 221 |
| 142 void AsyncPixelTransferDelegateStub::WaitForTransferCompletion( | 222 void AsyncPixelTransferDelegateStub::WaitForTransferCompletion( |
| 143 AsyncPixelTransferState* state) { | 223 AsyncPixelTransferState* transfer_state) { |
| 144 // Already done. | 224 scoped_refptr<TransferStateInternalStub> state = |
| 225 static_cast<AsyncTransferStateStub*>(transfer_state)->internal_.get(); | |
| 226 | |
| 227 for (std::list<Transfer>::iterator iter = transfers_.begin(); | |
| 228 iter != transfers_.end(); ++iter) { | |
| 229 if (iter->state.get() != state) | |
| 230 continue; | |
| 231 | |
| 232 iter->task.Run(); | |
|
Sami
2013/03/07 16:57:19
Neat!
Is it worth wrapping this bit into PerformT
reveman
2013/03/07 20:21:04
Done. Added ProcessTransfer.
| |
| 233 while (!iter->notifications.empty()) { | |
| 234 iter->notifications.front().Run(); | |
| 235 iter->notifications.pop(); | |
| 236 } | |
| 237 transfers_.erase(iter); | |
| 238 break; | |
| 239 } | |
| 145 } | 240 } |
| 146 | 241 |
| 147 uint32 AsyncPixelTransferDelegateStub::GetTextureUploadCount() { | 242 uint32 AsyncPixelTransferDelegateStub::GetTextureUploadCount() { |
| 148 return texture_upload_count_; | 243 return texture_upload_count_; |
| 149 } | 244 } |
| 150 | 245 |
| 151 base::TimeDelta AsyncPixelTransferDelegateStub::GetTotalTextureUploadTime() { | 246 base::TimeDelta AsyncPixelTransferDelegateStub::GetTotalTextureUploadTime() { |
| 152 return total_texture_upload_time_; | 247 return total_texture_upload_time_; |
| 153 } | 248 } |
| 154 | 249 |
| 250 void AsyncPixelTransferDelegateStub::ProcessPendingTransfers() { | |
| 251 if (transfers_.empty()) | |
| 252 return; | |
| 253 | |
| 254 transfers_.front().task.Run(); | |
| 255 while (!transfers_.front().notifications.empty()) { | |
| 256 transfers_.front().notifications.front().Run(); | |
| 257 transfers_.front().notifications.pop(); | |
| 258 } | |
| 259 transfers_.pop_front(); | |
| 260 } | |
| 261 | |
| 262 bool AsyncPixelTransferDelegateStub::HasPendingTransfers() { | |
| 263 return !transfers_.empty(); | |
| 264 } | |
| 265 | |
| 266 void AsyncPixelTransferDelegateStub::PerformNotifyCompletion( | |
| 267 AsyncMemoryParams mem_params, | |
| 268 ScopedSafeSharedMemory* safe_shared_memory, | |
| 269 const CompletionCallback& callback) { | |
| 270 TRACE_EVENT0("gpu", "PerformNotifyCompletion"); | |
| 271 gfx::AsyncMemoryParams safe_mem_params = mem_params; | |
| 272 safe_mem_params.shared_memory = safe_shared_memory->shared_memory(); | |
| 273 callback.Run(safe_mem_params); | |
| 274 } | |
| 275 | |
| 276 void AsyncPixelTransferDelegateStub::PerformAsyncTexImage2D( | |
| 277 scoped_refptr<TransferStateInternalStub> state, | |
| 278 AsyncTexImage2DParams tex_params, | |
| 279 AsyncMemoryParams mem_params, | |
| 280 ScopedSafeSharedMemory* safe_shared_memory) { | |
| 281 TRACE_EVENT2("gpu", "PerformAsyncTexImage2D", | |
| 282 "width", tex_params.width, | |
| 283 "height", tex_params.height); | |
| 284 DCHECK_EQ(0, tex_params.level); | |
| 285 | |
| 286 void* data = GetAddress(safe_shared_memory->shared_memory(), | |
| 287 mem_params.shm_data_offset); | |
| 288 | |
| 289 glActiveTexture(GL_TEXTURE0); | |
| 290 glBindTexture(GL_TEXTURE_2D, state->texture_id_); | |
| 291 | |
| 292 { | |
| 293 TRACE_EVENT0("gpu", "glTexImage2D"); | |
| 294 glTexImage2D( | |
| 295 tex_params.target, | |
| 296 tex_params.level, | |
| 297 tex_params.internal_format, | |
| 298 tex_params.width, | |
| 299 tex_params.height, | |
| 300 tex_params.border, | |
| 301 tex_params.format, | |
| 302 tex_params.type, | |
| 303 data); | |
| 304 } | |
| 305 | |
| 306 state->transfer_in_progress_ = false; | |
| 307 } | |
| 308 | |
| 309 void AsyncPixelTransferDelegateStub::PerformAsyncTexSubImage2D( | |
| 310 scoped_refptr<TransferStateInternalStub> state, | |
| 311 AsyncTexSubImage2DParams tex_params, | |
| 312 AsyncMemoryParams mem_params, | |
| 313 ScopedSafeSharedMemory* safe_shared_memory) { | |
| 314 TRACE_EVENT2("gpu", "PerformAsyncTexSubImage2D", | |
| 315 "width", tex_params.width, | |
| 316 "height", tex_params.height); | |
| 317 DCHECK_EQ(0, tex_params.level); | |
| 318 | |
| 319 void* data = GetAddress(safe_shared_memory->shared_memory(), | |
| 320 mem_params.shm_data_offset); | |
| 321 | |
| 322 base::TimeTicks begin_time(base::TimeTicks::HighResNow()); | |
| 323 glActiveTexture(GL_TEXTURE0); | |
| 324 glBindTexture(GL_TEXTURE_2D, state->texture_id_); | |
| 325 | |
| 326 { | |
| 327 TRACE_EVENT0("gpu", "glTexSubImage2D"); | |
| 328 glTexSubImage2D( | |
| 329 GL_TEXTURE_2D, | |
| 330 tex_params.level, | |
| 331 tex_params.xoffset, | |
| 332 tex_params.yoffset, | |
| 333 tex_params.width, | |
| 334 tex_params.height, | |
| 335 tex_params.format, | |
| 336 tex_params.type, | |
| 337 data); | |
| 338 } | |
| 339 | |
| 340 texture_upload_count_++; | |
| 341 total_texture_upload_time_ += base::TimeTicks::HighResNow() - begin_time; | |
| 342 | |
| 343 state->transfer_in_progress_ = false; | |
| 344 } | |
| 345 | |
| 155 } // namespace gfx | 346 } // namespace gfx |
| 156 | 347 |
| OLD | NEW |