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/debug/trace_event.h"
9 #include "base/debug/trace_event_synthetic_delay.h"
10 #include "base/lazy_instance.h"
11 #include "base/memory/weak_ptr.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 AsyncPixelTransferDelegateIdle(
36 AsyncPixelTransferManagerIdle::SharedState
* state
,
38 const AsyncTexImage2DParams
& define_params
);
39 virtual ~AsyncPixelTransferDelegateIdle();
41 // Implement AsyncPixelTransferDelegate:
42 virtual void AsyncTexImage2D(
43 const AsyncTexImage2DParams
& tex_params
,
44 const AsyncMemoryParams
& mem_params
,
45 const base::Closure
& bind_callback
) OVERRIDE
;
46 virtual void AsyncTexSubImage2D(
47 const AsyncTexSubImage2DParams
& tex_params
,
48 const AsyncMemoryParams
& mem_params
) OVERRIDE
;
49 virtual bool TransferIsInProgress() OVERRIDE
;
50 virtual void WaitForTransferCompletion() OVERRIDE
;
53 void PerformAsyncTexImage2D(AsyncTexImage2DParams tex_params
,
54 AsyncMemoryParams mem_params
,
55 const base::Closure
& bind_callback
);
56 void PerformAsyncTexSubImage2D(AsyncTexSubImage2DParams tex_params
,
57 AsyncMemoryParams mem_params
);
61 bool transfer_in_progress_
;
62 AsyncTexImage2DParams define_params_
;
64 // Safe to hold a raw pointer because SharedState is owned by the Manager
65 // which owns the Delegate.
66 AsyncPixelTransferManagerIdle::SharedState
* shared_state_
;
68 DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateIdle
);
71 AsyncPixelTransferDelegateIdle::AsyncPixelTransferDelegateIdle(
72 AsyncPixelTransferManagerIdle::SharedState
* shared_state
,
74 const AsyncTexImage2DParams
& define_params
)
75 : id_(g_next_pixel_transfer_state_id
++),
76 texture_id_(texture_id
),
77 transfer_in_progress_(false),
78 define_params_(define_params
),
79 shared_state_(shared_state
) {}
81 AsyncPixelTransferDelegateIdle::~AsyncPixelTransferDelegateIdle() {}
83 void AsyncPixelTransferDelegateIdle::AsyncTexImage2D(
84 const AsyncTexImage2DParams
& tex_params
,
85 const AsyncMemoryParams
& mem_params
,
86 const base::Closure
& bind_callback
) {
87 TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("gpu.AsyncTexImage");
88 DCHECK_EQ(static_cast<GLenum
>(GL_TEXTURE_2D
), tex_params
.target
);
90 shared_state_
->tasks
.push_back(AsyncPixelTransferManagerIdle::Task(
93 base::Bind(&AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D
,
99 transfer_in_progress_
= true;
102 void AsyncPixelTransferDelegateIdle::AsyncTexSubImage2D(
103 const AsyncTexSubImage2DParams
& tex_params
,
104 const AsyncMemoryParams
& mem_params
) {
105 TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("gpu.AsyncTexImage");
106 DCHECK_EQ(static_cast<GLenum
>(GL_TEXTURE_2D
), tex_params
.target
);
108 shared_state_
->tasks
.push_back(AsyncPixelTransferManagerIdle::Task(
111 base::Bind(&AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D
,
116 transfer_in_progress_
= true;
119 bool AsyncPixelTransferDelegateIdle::TransferIsInProgress() {
120 return transfer_in_progress_
;
123 void AsyncPixelTransferDelegateIdle::WaitForTransferCompletion() {
124 for (std::list
<AsyncPixelTransferManagerIdle::Task
>::iterator iter
=
125 shared_state_
->tasks
.begin();
126 iter
!= shared_state_
->tasks
.end();
128 if (iter
->transfer_id
!= id_
)
132 shared_state_
->tasks
.erase(iter
);
136 shared_state_
->ProcessNotificationTasks();
139 void AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D(
140 AsyncTexImage2DParams tex_params
,
141 AsyncMemoryParams mem_params
,
142 const base::Closure
& bind_callback
) {
143 TRACE_EVENT2("gpu", "PerformAsyncTexImage2D",
144 "width", tex_params
.width
,
145 "height", tex_params
.height
);
147 void* data
= mem_params
.GetDataAddress();
149 base::TimeTicks
begin_time(base::TimeTicks::HighResNow());
150 gfx::ScopedTextureBinder
texture_binder(tex_params
.target
, texture_id_
);
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::HighResNow() - 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::HighResNow());
186 gfx::ScopedTextureBinder
texture_binder(tex_params
.target
, texture_id_
);
188 // If it's a full texture update, use glTexImage2D as it's faster.
189 // TODO(epenner): Make this configurable (http://crbug.com/259924)
190 if (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::HighResNow() - 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 : texture_upload_count(0) {}
242 AsyncPixelTransferManagerIdle::SharedState::~SharedState() {}
244 void AsyncPixelTransferManagerIdle::SharedState::ProcessNotificationTasks() {
245 while (!tasks
.empty()) {
246 // Stop when we reach a pixel transfer task.
247 if (tasks
.front().transfer_id
)
250 tasks
.front().task
.Run();
255 AsyncPixelTransferManagerIdle::AsyncPixelTransferManagerIdle()
259 AsyncPixelTransferManagerIdle::~AsyncPixelTransferManagerIdle() {}
261 void AsyncPixelTransferManagerIdle::BindCompletedAsyncTransfers() {
262 // Everything is already bound.
265 void AsyncPixelTransferManagerIdle::AsyncNotifyCompletion(
266 const AsyncMemoryParams
& mem_params
,
267 AsyncPixelTransferCompletionObserver
* observer
) {
268 if (shared_state_
.tasks
.empty()) {
269 observer
->DidComplete(mem_params
);
273 shared_state_
.tasks
.push_back(
274 Task(0, // 0 transfer_id for notification tasks.
277 &PerformNotifyCompletion
,
279 make_scoped_refptr(observer
))));
282 uint32
AsyncPixelTransferManagerIdle::GetTextureUploadCount() {
283 return shared_state_
.texture_upload_count
;
286 base::TimeDelta
AsyncPixelTransferManagerIdle::GetTotalTextureUploadTime() {
287 return shared_state_
.total_texture_upload_time
;
290 void AsyncPixelTransferManagerIdle::ProcessMorePendingTransfers() {
291 if (shared_state_
.tasks
.empty())
294 // First task should always be a pixel transfer task.
295 DCHECK(shared_state_
.tasks
.front().transfer_id
);
296 shared_state_
.tasks
.front().task
.Run();
297 shared_state_
.tasks
.pop_front();
299 shared_state_
.ProcessNotificationTasks();
302 bool AsyncPixelTransferManagerIdle::NeedsProcessMorePendingTransfers() {
303 return !shared_state_
.tasks
.empty();
306 void AsyncPixelTransferManagerIdle::WaitAllAsyncTexImage2D() {
307 if (shared_state_
.tasks
.empty())
310 const Task
& task
= shared_state_
.tasks
.back();
312 task
.delegate
->WaitForTransferCompletion();
315 AsyncPixelTransferDelegate
*
316 AsyncPixelTransferManagerIdle::CreatePixelTransferDelegateImpl(
317 gles2::TextureRef
* ref
,
318 const AsyncTexImage2DParams
& define_params
) {
319 return new AsyncPixelTransferDelegateIdle(&shared_state_
,