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.
5 #include "gpu/command_buffer/service/async_pixel_transfer_manager_idle.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"
18 static uint64 g_next_pixel_transfer_state_id
= 1;
20 void PerformNotifyCompletion(
21 AsyncMemoryParams mem_params
,
22 scoped_refptr
<AsyncPixelTransferCompletionObserver
> observer
) {
23 TRACE_EVENT0("gpu", "PerformNotifyCompletion");
24 observer
->DidComplete(mem_params
);
29 // Class which handles async pixel transfers in a platform
31 class AsyncPixelTransferDelegateIdle
32 : public AsyncPixelTransferDelegate
,
33 public base::SupportsWeakPtr
<AsyncPixelTransferDelegateIdle
> {
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
;
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
;
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
);
59 TextureIdCallback texture_id_callback_
;
60 bool transfer_in_progress_
;
61 AsyncTexImage2DParams define_params_
;
63 // Safe to hold a raw pointer because SharedState is owned by the Manager
64 // which owns the Delegate.
65 AsyncPixelTransferManagerIdle::SharedState
* shared_state_
;
67 DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateIdle
);
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
) {}
80 AsyncPixelTransferDelegateIdle::~AsyncPixelTransferDelegateIdle() {}
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
);
89 shared_state_
->tasks
.push_back(AsyncPixelTransferManagerIdle::Task(
92 base::Bind(&AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D
,
98 transfer_in_progress_
= true;
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
);
107 shared_state_
->tasks
.push_back(AsyncPixelTransferManagerIdle::Task(
110 base::Bind(&AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D
,
115 transfer_in_progress_
= true;
118 bool AsyncPixelTransferDelegateIdle::TransferIsInProgress() {
119 return transfer_in_progress_
;
122 void AsyncPixelTransferDelegateIdle::WaitForTransferCompletion() {
123 for (std::list
<AsyncPixelTransferManagerIdle::Task
>::iterator iter
=
124 shared_state_
->tasks
.begin();
125 iter
!= shared_state_
->tasks
.end();
127 if (iter
->transfer_id
!= id_
)
131 shared_state_
->tasks
.erase(iter
);
135 shared_state_
->ProcessNotificationTasks();
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
);
146 void* data
= mem_params
.GetDataAddress();
148 base::TimeTicks
begin_time(base::TimeTicks::Now());
149 gfx::ScopedTextureBinder
texture_binder(tex_params
.target
,
150 texture_id_callback_
.Run());
153 TRACE_EVENT0("gpu", "glTexImage2D");
157 tex_params
.internal_format
,
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
;
172 // The texture is already fully bound so just call it now.
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
);
183 void* data
= mem_params
.GetDataAddress();
185 base::TimeTicks
begin_time(base::TimeTicks::Now());
186 gfx::ScopedTextureBinder
texture_binder(tex_params
.target
,
187 texture_id_callback_
.Run());
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");
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
,
208 TRACE_EVENT0("gpu", "glTexSubImage2D");
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
;
228 AsyncPixelTransferManagerIdle::Task::Task(
230 AsyncPixelTransferDelegate
* delegate
,
231 const base::Closure
& task
)
232 : transfer_id(transfer_id
),
237 AsyncPixelTransferManagerIdle::Task::~Task() {}
239 AsyncPixelTransferManagerIdle::SharedState::SharedState(
240 bool use_teximage2d_over_texsubimage2d
)
241 : use_teximage2d_over_texsubimage2d(use_teximage2d_over_texsubimage2d
),
242 texture_upload_count(0) {
245 AsyncPixelTransferManagerIdle::SharedState::~SharedState() {}
247 void AsyncPixelTransferManagerIdle::SharedState::ProcessNotificationTasks() {
248 while (!tasks
.empty()) {
249 // Stop when we reach a pixel transfer task.
250 if (tasks
.front().transfer_id
)
253 tasks
.front().task
.Run();
258 AsyncPixelTransferManagerIdle::AsyncPixelTransferManagerIdle(
259 bool use_teximage2d_over_texsubimage2d
)
260 : shared_state_(use_teximage2d_over_texsubimage2d
) {
263 AsyncPixelTransferManagerIdle::~AsyncPixelTransferManagerIdle() {}
265 void AsyncPixelTransferManagerIdle::BindCompletedAsyncTransfers() {
266 // Everything is already bound.
269 void AsyncPixelTransferManagerIdle::AsyncNotifyCompletion(
270 const AsyncMemoryParams
& mem_params
,
271 AsyncPixelTransferCompletionObserver
* observer
) {
272 if (shared_state_
.tasks
.empty()) {
273 observer
->DidComplete(mem_params
);
277 shared_state_
.tasks
.push_back(
278 Task(0, // 0 transfer_id for notification tasks.
281 &PerformNotifyCompletion
,
283 make_scoped_refptr(observer
))));
286 uint32
AsyncPixelTransferManagerIdle::GetTextureUploadCount() {
287 return shared_state_
.texture_upload_count
;
290 base::TimeDelta
AsyncPixelTransferManagerIdle::GetTotalTextureUploadTime() {
291 return shared_state_
.total_texture_upload_time
;
294 void AsyncPixelTransferManagerIdle::ProcessMorePendingTransfers() {
295 if (shared_state_
.tasks
.empty())
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();
303 shared_state_
.ProcessNotificationTasks();
306 bool AsyncPixelTransferManagerIdle::NeedsProcessMorePendingTransfers() {
307 return !shared_state_
.tasks
.empty();
310 void AsyncPixelTransferManagerIdle::WaitAllAsyncTexImage2D() {
311 if (shared_state_
.tasks
.empty())
314 const Task
& task
= shared_state_
.tasks
.back();
316 task
.delegate
->WaitForTransferCompletion();
319 AsyncPixelTransferDelegate
*
320 AsyncPixelTransferManagerIdle::CreatePixelTransferDelegateImpl(
321 gles2::TextureRef
* ref
,
322 const AsyncTexImage2DParams
& define_params
) {
323 return new AsyncPixelTransferDelegateIdle(
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
330 base::Bind(&gles2::TextureRef::service_id
, base::Unretained(ref
)),