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 |