OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 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 "ui/gl/async_pixel_transfer_delegate_idle.h" | |
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" | |
12 #include "base/shared_memory.h" | |
13 #include "build/build_config.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" | |
19 | |
20 using base::SharedMemory; | |
21 using base::SharedMemoryHandle; | |
22 | |
23 namespace gfx { | |
24 | |
25 namespace { | |
26 | |
27 // Gets the address of the data from shared memory. | |
28 void* GetAddress(SharedMemory* shared_memory, uint32 shm_data_offset) { | |
29 // Memory bounds have already been validated, so there | |
30 // is just DCHECKS here. | |
31 DCHECK(shared_memory); | |
32 DCHECK(shared_memory->memory()); | |
33 return static_cast<int8*>(shared_memory->memory()) + shm_data_offset; | |
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 | |
43 } // namespace | |
44 | |
45 #if !defined(OS_ANDROID) | |
46 scoped_ptr<AsyncPixelTransferDelegate> | |
47 AsyncPixelTransferDelegate::Create(gfx::GLContext* context) { | |
48 return AsyncPixelTransferDelegateIdle::Create(context); | |
49 } | |
50 #endif | |
51 | |
52 scoped_ptr<AsyncPixelTransferDelegate> | |
53 AsyncPixelTransferDelegateIdle::Create(gfx::GLContext* context) { | |
54 return make_scoped_ptr( | |
55 static_cast<AsyncPixelTransferDelegate*>( | |
56 new AsyncPixelTransferDelegateIdle())); | |
57 } | |
58 | |
59 // Class which holds async pixel transfers state. | |
60 class TransferStateInternalIdle | |
61 : public base::RefCounted<TransferStateInternalIdle> { | |
62 public: | |
63 explicit TransferStateInternalIdle(GLuint texture_id) | |
64 : texture_id_(texture_id), | |
65 transfer_in_progress_(false) { | |
66 } | |
67 | |
68 // Implement AsyncPixelTransferState: | |
69 bool TransferIsInProgress() { | |
70 return transfer_in_progress_; | |
71 } | |
72 | |
73 protected: | |
74 friend class base::RefCounted<TransferStateInternalIdle>; | |
75 friend class AsyncPixelTransferDelegateIdle; | |
76 | |
77 virtual ~TransferStateInternalIdle() {} | |
78 | |
79 GLuint texture_id_; | |
80 | |
81 // Indicates that an async transfer is in progress. | |
82 bool transfer_in_progress_; | |
83 }; | |
84 | |
85 // This just wraps an internal ref-counted state object. | |
86 class AsyncTransferStateIdle : public AsyncPixelTransferState { | |
epenner
2013/03/13 18:58:01
See my comment on the transfers_ list in the heade
reveman
2013/03/14 01:12:45
Internal class gone in latest patch.
| |
87 public: | |
88 explicit AsyncTransferStateIdle(GLuint texture_id) | |
89 : internal_(new TransferStateInternalIdle(texture_id)) { | |
90 } | |
91 virtual ~AsyncTransferStateIdle() {} | |
92 virtual bool TransferIsInProgress() { | |
93 return internal_->TransferIsInProgress(); | |
94 } | |
95 scoped_refptr<TransferStateInternalIdle> internal_; | |
96 }; | |
97 | |
98 AsyncPixelTransferDelegateIdle::Transfer::Transfer( | |
99 TransferStateInternalIdle* state, | |
100 const base::Closure& task) | |
101 : state(state), | |
102 task(task) { | |
103 } | |
104 | |
105 AsyncPixelTransferDelegateIdle::Transfer::~Transfer() {} | |
106 | |
107 AsyncPixelTransferDelegateIdle::AsyncPixelTransferDelegateIdle() | |
108 : texture_upload_count_(0), | |
109 texture_dirty_(false) { | |
110 } | |
111 | |
112 AsyncPixelTransferDelegateIdle::~AsyncPixelTransferDelegateIdle() { | |
113 } | |
114 | |
115 AsyncPixelTransferState* | |
116 AsyncPixelTransferDelegateIdle::CreateRawPixelTransferState( | |
117 GLuint texture_id, | |
118 const AsyncTexImage2DParams& define_params) { | |
119 return static_cast<AsyncPixelTransferState*>( | |
120 new AsyncTransferStateIdle(texture_id)); | |
121 } | |
122 | |
123 bool AsyncPixelTransferDelegateIdle::BindCompletedAsyncTransfers() { | |
124 bool texture_dirty = texture_dirty_; | |
epenner
2013/03/13 18:58:01
This feels brittle to me and not implied from the
reveman
2013/03/14 01:12:45
I made ProcessMorePendingTransfers() have a return
| |
125 texture_dirty_ = false; | |
126 return texture_dirty; | |
127 } | |
128 | |
129 void AsyncPixelTransferDelegateIdle::AsyncNotifyCompletion( | |
130 const AsyncMemoryParams& mem_params, | |
131 const CompletionCallback& callback) { | |
132 if (transfers_.empty()) { | |
133 callback.Run(mem_params); | |
134 return; | |
135 } | |
136 | |
137 transfers_.back().notifications.push( | |
138 base::Bind( | |
139 &AsyncPixelTransferDelegateIdle::PerformNotifyCompletion, | |
140 AsWeakPtr(), | |
141 mem_params, | |
142 base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(), | |
143 mem_params.shared_memory, | |
144 mem_params.shm_size)), | |
145 callback)); | |
146 } | |
147 | |
148 void AsyncPixelTransferDelegateIdle::AsyncTexImage2D( | |
149 AsyncPixelTransferState* transfer_state, | |
150 const AsyncTexImage2DParams& tex_params, | |
151 const AsyncMemoryParams& mem_params, | |
152 const base::Closure& bind_callback) { | |
153 scoped_refptr<TransferStateInternalIdle> state = | |
154 static_cast<AsyncTransferStateIdle*>(transfer_state)->internal_.get(); | |
155 DCHECK(mem_params.shared_memory); | |
156 DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size, | |
157 mem_params.shm_size); | |
158 DCHECK(state); | |
159 DCHECK(state->texture_id_); | |
160 | |
161 transfers_.push_back( | |
162 Transfer( | |
163 state.get(), | |
164 base::Bind( | |
165 &AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D, | |
166 AsWeakPtr(), | |
167 state, | |
168 tex_params, | |
169 mem_params, | |
170 bind_callback, | |
171 base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(), | |
172 mem_params.shared_memory, | |
173 mem_params.shm_size))))); | |
174 | |
175 state->transfer_in_progress_ = true; | |
176 } | |
177 | |
178 void AsyncPixelTransferDelegateIdle::AsyncTexSubImage2D( | |
179 AsyncPixelTransferState* transfer_state, | |
180 const AsyncTexSubImage2DParams& tex_params, | |
181 const AsyncMemoryParams& mem_params) { | |
182 scoped_refptr<TransferStateInternalIdle> state = | |
183 static_cast<AsyncTransferStateIdle*>(transfer_state)->internal_.get(); | |
184 DCHECK(mem_params.shared_memory); | |
185 DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size, | |
186 mem_params.shm_size); | |
187 DCHECK(state); | |
188 DCHECK(state->texture_id_); | |
189 | |
190 transfers_.push_back( | |
191 Transfer( | |
192 state.get(), | |
193 base::Bind( | |
194 &AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D, | |
195 AsWeakPtr(), | |
196 state, | |
197 tex_params, | |
198 mem_params, | |
199 base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(), | |
200 mem_params.shared_memory, | |
201 mem_params.shm_size))))); | |
202 | |
203 state->transfer_in_progress_ = true; | |
204 } | |
205 | |
206 void AsyncPixelTransferDelegateIdle::WaitForTransferCompletion( | |
207 AsyncPixelTransferState* transfer_state) { | |
208 scoped_refptr<TransferStateInternalIdle> state = | |
209 static_cast<AsyncTransferStateIdle*>(transfer_state)->internal_.get(); | |
210 | |
211 for (std::list<Transfer>::iterator iter = transfers_.begin(); | |
212 iter != transfers_.end(); ++iter) { | |
213 if (iter->state.get() != state) | |
214 continue; | |
215 | |
216 ProcessTransfer(*iter); | |
217 transfers_.erase(iter); | |
218 break; | |
219 } | |
220 } | |
221 | |
222 uint32 AsyncPixelTransferDelegateIdle::GetTextureUploadCount() { | |
223 return texture_upload_count_; | |
224 } | |
225 | |
226 base::TimeDelta AsyncPixelTransferDelegateIdle::GetTotalTextureUploadTime() { | |
227 return total_texture_upload_time_; | |
228 } | |
229 | |
230 void AsyncPixelTransferDelegateIdle::ProcessPendingTransfers() { | |
231 if (transfers_.empty()) | |
232 return; | |
233 | |
234 ProcessTransfer(transfers_.front()); | |
235 transfers_.pop_front(); | |
236 } | |
237 | |
238 bool AsyncPixelTransferDelegateIdle::NeedsProcessPendingTransfers() { | |
239 return !transfers_.empty(); | |
240 } | |
241 | |
242 void AsyncPixelTransferDelegateIdle::ProcessTransfer(Transfer& transfer) { | |
243 transfer.task.Run(); | |
244 while (!transfer.notifications.empty()) { | |
245 transfer.notifications.front().Run(); | |
246 transfer.notifications.pop(); | |
247 } | |
248 } | |
249 | |
250 void AsyncPixelTransferDelegateIdle::PerformNotifyCompletion( | |
251 AsyncMemoryParams mem_params, | |
252 ScopedSafeSharedMemory* safe_shared_memory, | |
253 const CompletionCallback& callback) { | |
254 TRACE_EVENT0("gpu", "PerformNotifyCompletion"); | |
255 gfx::AsyncMemoryParams safe_mem_params = mem_params; | |
256 safe_mem_params.shared_memory = safe_shared_memory->shared_memory(); | |
257 callback.Run(safe_mem_params); | |
258 } | |
259 | |
260 void AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D( | |
261 scoped_refptr<TransferStateInternalIdle> state, | |
262 AsyncTexImage2DParams tex_params, | |
263 AsyncMemoryParams mem_params, | |
264 const base::Closure& bind_callback, | |
265 ScopedSafeSharedMemory* safe_shared_memory) { | |
266 TRACE_EVENT2("gpu", "PerformAsyncTexImage2D", | |
267 "width", tex_params.width, | |
268 "height", tex_params.height); | |
269 DCHECK_EQ(0, tex_params.level); | |
270 | |
271 void* data = GetAddress(safe_shared_memory->shared_memory(), | |
272 mem_params.shm_data_offset); | |
273 | |
274 glActiveTexture(GL_TEXTURE0); | |
275 glBindTexture(GL_TEXTURE_2D, state->texture_id_); | |
276 texture_dirty_ = true; | |
277 | |
278 { | |
279 TRACE_EVENT0("gpu", "glTexImage2D"); | |
280 glTexImage2D( | |
281 tex_params.target, | |
282 tex_params.level, | |
283 tex_params.internal_format, | |
284 tex_params.width, | |
285 tex_params.height, | |
286 tex_params.border, | |
287 tex_params.format, | |
288 tex_params.type, | |
289 data); | |
290 } | |
291 | |
292 state->transfer_in_progress_ = false; | |
293 | |
294 // The texture is already fully bound so just call it now. | |
295 bind_callback.Run(); | |
epenner
2013/03/13 18:58:01
Same comment on possible use-after-free when invok
reveman
2013/03/14 01:12:45
Done.
| |
296 } | |
297 | |
298 void AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D( | |
299 scoped_refptr<TransferStateInternalIdle> state, | |
300 AsyncTexSubImage2DParams tex_params, | |
301 AsyncMemoryParams mem_params, | |
302 ScopedSafeSharedMemory* safe_shared_memory) { | |
303 TRACE_EVENT2("gpu", "PerformAsyncTexSubImage2D", | |
304 "width", tex_params.width, | |
305 "height", tex_params.height); | |
306 DCHECK_EQ(0, tex_params.level); | |
307 | |
308 void* data = GetAddress(safe_shared_memory->shared_memory(), | |
309 mem_params.shm_data_offset); | |
310 | |
311 base::TimeTicks begin_time(base::TimeTicks::HighResNow()); | |
312 glActiveTexture(GL_TEXTURE0); | |
313 glBindTexture(GL_TEXTURE_2D, state->texture_id_); | |
314 texture_dirty_ = true; | |
315 | |
316 { | |
317 TRACE_EVENT0("gpu", "glTexSubImage2D"); | |
318 glTexSubImage2D( | |
319 GL_TEXTURE_2D, | |
320 tex_params.level, | |
321 tex_params.xoffset, | |
322 tex_params.yoffset, | |
323 tex_params.width, | |
324 tex_params.height, | |
325 tex_params.format, | |
326 tex_params.type, | |
327 data); | |
328 } | |
329 | |
330 texture_upload_count_++; | |
331 total_texture_upload_time_ += base::TimeTicks::HighResNow() - begin_time; | |
332 | |
333 state->transfer_in_progress_ = false; | |
334 } | |
335 | |
336 } // namespace gfx | |
OLD | NEW |