Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / common / gpu / client / command_buffer_proxy_impl.cc
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
3 // found in the LICENSE file.
4
5 #include "content/common/gpu/client/command_buffer_proxy_impl.h"
6
7 #include "base/callback.h"
8 #include "base/debug/trace_event.h"
9 #include "base/logging.h"
10 #include "base/memory/shared_memory.h"
11 #include "base/stl_util.h"
12 #include "content/common/child_process_messages.h"
13 #include "content/common/gpu/client/gpu_channel_host.h"
14 #include "content/common/gpu/client/gpu_video_decode_accelerator_host.h"
15 #include "content/common/gpu/client/gpu_video_encode_accelerator_host.h"
16 #include "content/common/gpu/gpu_messages.h"
17 #include "content/common/view_messages.h"
18 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
19 #include "gpu/command_buffer/common/cmd_buffer_common.h"
20 #include "gpu/command_buffer/common/command_buffer_shared.h"
21 #include "gpu/command_buffer/common/gpu_memory_allocation.h"
22 #include "gpu/command_buffer/service/image_factory.h"
23 #include "ui/gfx/size.h"
24 #include "ui/gl/gl_bindings.h"
25
26 namespace content {
27
28 CommandBufferProxyImpl::CommandBufferProxyImpl(
29     GpuChannelHost* channel,
30     int route_id)
31     : channel_(channel),
32       route_id_(route_id),
33       flush_count_(0),
34       last_put_offset_(-1),
35       next_signal_id_(0) {
36 }
37
38 CommandBufferProxyImpl::~CommandBufferProxyImpl() {
39   FOR_EACH_OBSERVER(DeletionObserver,
40                     deletion_observers_,
41                     OnWillDeleteImpl());
42 }
43
44 bool CommandBufferProxyImpl::OnMessageReceived(const IPC::Message& message) {
45   bool handled = true;
46   IPC_BEGIN_MESSAGE_MAP(CommandBufferProxyImpl, message)
47     IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_Destroyed, OnDestroyed);
48     IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_ConsoleMsg, OnConsoleMessage);
49     IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SetMemoryAllocation,
50                         OnSetMemoryAllocation);
51     IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SignalSyncPointAck,
52                         OnSignalSyncPointAck);
53     IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SwapBuffersCompleted,
54                         OnSwapBuffersCompleted);
55     IPC_MESSAGE_UNHANDLED(handled = false)
56   IPC_END_MESSAGE_MAP()
57
58   DCHECK(handled);
59   return handled;
60 }
61
62 void CommandBufferProxyImpl::OnChannelError() {
63   OnDestroyed(gpu::error::kUnknown);
64 }
65
66 void CommandBufferProxyImpl::OnDestroyed(gpu::error::ContextLostReason reason) {
67   // Prevent any further messages from being sent.
68   channel_ = NULL;
69
70   // When the client sees that the context is lost, they should delete this
71   // CommandBufferProxyImpl and create a new one.
72   last_state_.error = gpu::error::kLostContext;
73   last_state_.context_lost_reason = reason;
74
75   if (!channel_error_callback_.is_null()) {
76     channel_error_callback_.Run();
77     // Avoid calling the error callback more than once.
78     channel_error_callback_.Reset();
79   }
80 }
81
82 void CommandBufferProxyImpl::OnConsoleMessage(
83     const GPUCommandBufferConsoleMessage& message) {
84   if (!console_message_callback_.is_null()) {
85     console_message_callback_.Run(message.message, message.id);
86   }
87 }
88
89 void CommandBufferProxyImpl::SetMemoryAllocationChangedCallback(
90     const MemoryAllocationChangedCallback& callback) {
91   if (last_state_.error != gpu::error::kNoError)
92     return;
93
94   memory_allocation_changed_callback_ = callback;
95   Send(new GpuCommandBufferMsg_SetClientHasMemoryAllocationChangedCallback(
96       route_id_, !memory_allocation_changed_callback_.is_null()));
97 }
98
99 void CommandBufferProxyImpl::AddDeletionObserver(DeletionObserver* observer) {
100   deletion_observers_.AddObserver(observer);
101 }
102
103 void CommandBufferProxyImpl::RemoveDeletionObserver(
104     DeletionObserver* observer) {
105   deletion_observers_.RemoveObserver(observer);
106 }
107
108 void CommandBufferProxyImpl::OnSetMemoryAllocation(
109     const gpu::MemoryAllocation& allocation) {
110   if (!memory_allocation_changed_callback_.is_null())
111     memory_allocation_changed_callback_.Run(allocation);
112 }
113
114 void CommandBufferProxyImpl::OnSignalSyncPointAck(uint32 id) {
115   SignalTaskMap::iterator it = signal_tasks_.find(id);
116   DCHECK(it != signal_tasks_.end());
117   base::Closure callback = it->second;
118   signal_tasks_.erase(it);
119   callback.Run();
120 }
121
122 void CommandBufferProxyImpl::SetChannelErrorCallback(
123     const base::Closure& callback) {
124   channel_error_callback_ = callback;
125 }
126
127 bool CommandBufferProxyImpl::Initialize() {
128   TRACE_EVENT0("gpu", "CommandBufferProxyImpl::Initialize");
129   shared_state_shm_.reset(channel_->factory()->AllocateSharedMemory(
130       sizeof(*shared_state())).release());
131   if (!shared_state_shm_)
132     return false;
133
134   if (!shared_state_shm_->Map(sizeof(*shared_state())))
135     return false;
136
137   shared_state()->Initialize();
138
139   // This handle is owned by the GPU process and must be passed to it or it
140   // will leak. In otherwords, do not early out on error between here and the
141   // sending of the Initialize IPC below.
142   base::SharedMemoryHandle handle =
143       channel_->ShareToGpuProcess(shared_state_shm_->handle());
144   if (!base::SharedMemory::IsHandleValid(handle))
145     return false;
146
147   bool result = false;
148   if (!Send(new GpuCommandBufferMsg_Initialize(
149       route_id_, handle, &result, &capabilities_))) {
150     LOG(ERROR) << "Could not send GpuCommandBufferMsg_Initialize.";
151     return false;
152   }
153
154   if (!result) {
155     LOG(ERROR) << "Failed to initialize command buffer service.";
156     return false;
157   }
158
159   capabilities_.image = true;
160
161   return true;
162 }
163
164 gpu::CommandBuffer::State CommandBufferProxyImpl::GetLastState() {
165   return last_state_;
166 }
167
168 int32 CommandBufferProxyImpl::GetLastToken() {
169   TryUpdateState();
170   return last_state_.token;
171 }
172
173 void CommandBufferProxyImpl::Flush(int32 put_offset) {
174   if (last_state_.error != gpu::error::kNoError)
175     return;
176
177   TRACE_EVENT1("gpu",
178                "CommandBufferProxyImpl::Flush",
179                "put_offset",
180                put_offset);
181
182   if (last_put_offset_ == put_offset)
183     return;
184
185   last_put_offset_ = put_offset;
186
187   Send(new GpuCommandBufferMsg_AsyncFlush(route_id_,
188                                           put_offset,
189                                           ++flush_count_,
190                                           latency_info_));
191   latency_info_.clear();
192 }
193
194 void CommandBufferProxyImpl::SetLatencyInfo(
195     const std::vector<ui::LatencyInfo>& latency_info) {
196   for (size_t i = 0; i < latency_info.size(); i++)
197     latency_info_.push_back(latency_info[i]);
198 }
199
200 void CommandBufferProxyImpl::SetSwapBuffersCompletionCallback(
201     const SwapBuffersCompletionCallback& callback) {
202   swap_buffers_completion_callback_ = callback;
203 }
204
205 void CommandBufferProxyImpl::WaitForTokenInRange(int32 start, int32 end) {
206   TRACE_EVENT2("gpu",
207                "CommandBufferProxyImpl::WaitForToken",
208                "start",
209                start,
210                "end",
211                end);
212   TryUpdateState();
213   if (!InRange(start, end, last_state_.token) &&
214       last_state_.error == gpu::error::kNoError) {
215     gpu::CommandBuffer::State state;
216     if (Send(new GpuCommandBufferMsg_WaitForTokenInRange(
217             route_id_, start, end, &state)))
218       OnUpdateState(state);
219   }
220   DCHECK(InRange(start, end, last_state_.token) ||
221          last_state_.error != gpu::error::kNoError);
222 }
223
224 void CommandBufferProxyImpl::WaitForGetOffsetInRange(int32 start, int32 end) {
225   TRACE_EVENT2("gpu",
226                "CommandBufferProxyImpl::WaitForGetOffset",
227                "start",
228                start,
229                "end",
230                end);
231   TryUpdateState();
232   if (!InRange(start, end, last_state_.get_offset) &&
233       last_state_.error == gpu::error::kNoError) {
234     gpu::CommandBuffer::State state;
235     if (Send(new GpuCommandBufferMsg_WaitForGetOffsetInRange(
236             route_id_, start, end, &state)))
237       OnUpdateState(state);
238   }
239   DCHECK(InRange(start, end, last_state_.get_offset) ||
240          last_state_.error != gpu::error::kNoError);
241 }
242
243 void CommandBufferProxyImpl::SetGetBuffer(int32 shm_id) {
244   if (last_state_.error != gpu::error::kNoError)
245     return;
246
247   Send(new GpuCommandBufferMsg_SetGetBuffer(route_id_, shm_id));
248   last_put_offset_ = -1;
249 }
250
251 scoped_refptr<gpu::Buffer> CommandBufferProxyImpl::CreateTransferBuffer(
252     size_t size,
253     int32* id) {
254   *id = -1;
255
256   if (last_state_.error != gpu::error::kNoError)
257     return NULL;
258
259   int32 new_id = channel_->ReserveTransferBufferId();
260
261   scoped_ptr<base::SharedMemory> shared_memory(
262       channel_->factory()->AllocateSharedMemory(size));
263   if (!shared_memory)
264     return NULL;
265
266   DCHECK(!shared_memory->memory());
267   if (!shared_memory->Map(size))
268     return NULL;
269
270   // This handle is owned by the GPU process and must be passed to it or it
271   // will leak. In otherwords, do not early out on error between here and the
272   // sending of the RegisterTransferBuffer IPC below.
273   base::SharedMemoryHandle handle =
274       channel_->ShareToGpuProcess(shared_memory->handle());
275   if (!base::SharedMemory::IsHandleValid(handle))
276     return NULL;
277
278   if (!Send(new GpuCommandBufferMsg_RegisterTransferBuffer(route_id_,
279                                                            new_id,
280                                                            handle,
281                                                            size))) {
282     return NULL;
283   }
284
285   *id = new_id;
286   scoped_refptr<gpu::Buffer> buffer(
287       gpu::MakeBufferFromSharedMemory(shared_memory.Pass(), size));
288   return buffer;
289 }
290
291 void CommandBufferProxyImpl::DestroyTransferBuffer(int32 id) {
292   if (last_state_.error != gpu::error::kNoError)
293     return;
294
295   Send(new GpuCommandBufferMsg_DestroyTransferBuffer(route_id_, id));
296 }
297
298 gpu::Capabilities CommandBufferProxyImpl::GetCapabilities() {
299   return capabilities_;
300 }
301
302 int32_t CommandBufferProxyImpl::CreateImage(ClientBuffer buffer,
303                                             size_t width,
304                                             size_t height,
305                                             unsigned internalformat) {
306   if (last_state_.error != gpu::error::kNoError)
307     return -1;
308
309   int32 new_id = channel_->ReserveImageId();
310
311   gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager =
312       channel_->gpu_memory_buffer_manager();
313   gfx::GpuMemoryBuffer* gpu_memory_buffer =
314       gpu_memory_buffer_manager->GpuMemoryBufferFromClientBuffer(buffer);
315   DCHECK(gpu_memory_buffer);
316
317   // This handle is owned by the GPU process and must be passed to it or it
318   // will leak. In otherwords, do not early out on error between here and the
319   // sending of the CreateImage IPC below.
320   bool requires_sync_point = false;
321   gfx::GpuMemoryBufferHandle handle =
322       channel_->ShareGpuMemoryBufferToGpuProcess(gpu_memory_buffer->GetHandle(),
323                                                  &requires_sync_point);
324
325   DCHECK(gpu::ImageFactory::IsImageFormatCompatibleWithGpuMemoryBufferFormat(
326       internalformat, gpu_memory_buffer->GetFormat()));
327   if (!Send(new GpuCommandBufferMsg_CreateImage(route_id_,
328                                                 new_id,
329                                                 handle,
330                                                 gfx::Size(width, height),
331                                                 gpu_memory_buffer->GetFormat(),
332                                                 internalformat))) {
333     return -1;
334   }
335
336   if (requires_sync_point) {
337     gpu_memory_buffer_manager->SetDestructionSyncPoint(gpu_memory_buffer,
338                                                        InsertSyncPoint());
339   }
340
341   return new_id;
342 }
343
344 void CommandBufferProxyImpl::DestroyImage(int32 id) {
345   if (last_state_.error != gpu::error::kNoError)
346     return;
347
348   Send(new GpuCommandBufferMsg_DestroyImage(route_id_, id));
349 }
350
351 int32_t CommandBufferProxyImpl::CreateGpuMemoryBufferImage(
352     size_t width,
353     size_t height,
354     unsigned internalformat,
355     unsigned usage) {
356   scoped_ptr<gfx::GpuMemoryBuffer> buffer(
357       channel_->gpu_memory_buffer_manager()->AllocateGpuMemoryBuffer(
358           gfx::Size(width, height),
359           gpu::ImageFactory::ImageFormatToGpuMemoryBufferFormat(internalformat),
360           gpu::ImageFactory::ImageUsageToGpuMemoryBufferUsage(usage)));
361   if (!buffer)
362     return -1;
363
364   return CreateImage(buffer->AsClientBuffer(), width, height, internalformat);
365 }
366
367 int CommandBufferProxyImpl::GetRouteID() const {
368   return route_id_;
369 }
370
371 uint32 CommandBufferProxyImpl::CreateStreamTexture(uint32 texture_id) {
372   if (last_state_.error != gpu::error::kNoError)
373     return 0;
374
375   int32 stream_id = channel_->GenerateRouteID();
376   bool succeeded = false;
377   Send(new GpuCommandBufferMsg_CreateStreamTexture(
378       route_id_, texture_id, stream_id, &succeeded));
379   if (!succeeded) {
380     DLOG(ERROR) << "GpuCommandBufferMsg_CreateStreamTexture returned failure";
381     return 0;
382   }
383   return stream_id;
384 }
385
386 uint32 CommandBufferProxyImpl::InsertSyncPoint() {
387   if (last_state_.error != gpu::error::kNoError)
388     return 0;
389
390   uint32 sync_point = 0;
391   Send(new GpuCommandBufferMsg_InsertSyncPoint(route_id_, true, &sync_point));
392   return sync_point;
393 }
394
395 uint32_t CommandBufferProxyImpl::InsertFutureSyncPoint() {
396   if (last_state_.error != gpu::error::kNoError)
397     return 0;
398
399   uint32 sync_point = 0;
400   Send(new GpuCommandBufferMsg_InsertSyncPoint(route_id_, false, &sync_point));
401   return sync_point;
402 }
403
404 void CommandBufferProxyImpl::RetireSyncPoint(uint32_t sync_point) {
405   if (last_state_.error != gpu::error::kNoError)
406     return;
407
408   Send(new GpuCommandBufferMsg_RetireSyncPoint(route_id_, sync_point));
409 }
410
411 void CommandBufferProxyImpl::SignalSyncPoint(uint32 sync_point,
412                                              const base::Closure& callback) {
413   if (last_state_.error != gpu::error::kNoError)
414     return;
415
416   uint32 signal_id = next_signal_id_++;
417   if (!Send(new GpuCommandBufferMsg_SignalSyncPoint(route_id_,
418                                                     sync_point,
419                                                     signal_id))) {
420     return;
421   }
422
423   signal_tasks_.insert(std::make_pair(signal_id, callback));
424 }
425
426 void CommandBufferProxyImpl::SignalQuery(uint32 query,
427                                          const base::Closure& callback) {
428   if (last_state_.error != gpu::error::kNoError)
429     return;
430
431   // Signal identifiers are hidden, so nobody outside of this class will see
432   // them. (And thus, they cannot save them.) The IDs themselves only last
433   // until the callback is invoked, which will happen as soon as the GPU
434   // catches upwith the command buffer.
435   // A malicious caller trying to create a collision by making next_signal_id
436   // would have to make calls at an astounding rate (300B/s) and even if they
437   // could do that, all they would do is to prevent some callbacks from getting
438   // called, leading to stalled threads and/or memory leaks.
439   uint32 signal_id = next_signal_id_++;
440   if (!Send(new GpuCommandBufferMsg_SignalQuery(route_id_,
441                                                 query,
442                                                 signal_id))) {
443     return;
444   }
445
446   signal_tasks_.insert(std::make_pair(signal_id, callback));
447 }
448
449 void CommandBufferProxyImpl::SetSurfaceVisible(bool visible) {
450   if (last_state_.error != gpu::error::kNoError)
451     return;
452
453   Send(new GpuCommandBufferMsg_SetSurfaceVisible(route_id_, visible));
454 }
455
456 bool CommandBufferProxyImpl::ProduceFrontBuffer(const gpu::Mailbox& mailbox) {
457   if (last_state_.error != gpu::error::kNoError)
458     return false;
459
460   return Send(new GpuCommandBufferMsg_ProduceFrontBuffer(route_id_, mailbox));
461 }
462
463 scoped_ptr<media::VideoDecodeAccelerator>
464 CommandBufferProxyImpl::CreateVideoDecoder() {
465   if (!channel_)
466     return scoped_ptr<media::VideoDecodeAccelerator>();
467   return scoped_ptr<media::VideoDecodeAccelerator>(
468       new GpuVideoDecodeAcceleratorHost(channel_, this));
469 }
470
471 scoped_ptr<media::VideoEncodeAccelerator>
472 CommandBufferProxyImpl::CreateVideoEncoder() {
473   if (!channel_)
474     return scoped_ptr<media::VideoEncodeAccelerator>();
475   return scoped_ptr<media::VideoEncodeAccelerator>(
476       new GpuVideoEncodeAcceleratorHost(channel_, this));
477 }
478
479 gpu::error::Error CommandBufferProxyImpl::GetLastError() {
480   return last_state_.error;
481 }
482
483 bool CommandBufferProxyImpl::Send(IPC::Message* msg) {
484   // Caller should not intentionally send a message if the context is lost.
485   DCHECK(last_state_.error == gpu::error::kNoError);
486
487   if (channel_) {
488     if (channel_->Send(msg)) {
489       return true;
490     } else {
491       // Flag the command buffer as lost. Defer deleting the channel until
492       // OnChannelError is called after returning to the message loop in case
493       // it is referenced elsewhere.
494       DVLOG(1) << "CommandBufferProxyImpl::Send failed. Losing context.";
495       last_state_.error = gpu::error::kLostContext;
496       return false;
497     }
498   }
499
500   // Callee takes ownership of message, regardless of whether Send is
501   // successful. See IPC::Sender.
502   delete msg;
503   return false;
504 }
505
506 void CommandBufferProxyImpl::OnUpdateState(
507     const gpu::CommandBuffer::State& state) {
508   // Handle wraparound. It works as long as we don't have more than 2B state
509   // updates in flight across which reordering occurs.
510   if (state.generation - last_state_.generation < 0x80000000U)
511     last_state_ = state;
512 }
513
514 void CommandBufferProxyImpl::SetOnConsoleMessageCallback(
515     const GpuConsoleMessageCallback& callback) {
516   console_message_callback_ = callback;
517 }
518
519 void CommandBufferProxyImpl::TryUpdateState() {
520   if (last_state_.error == gpu::error::kNoError)
521     shared_state()->Read(&last_state_);
522 }
523
524 gpu::CommandBufferSharedState* CommandBufferProxyImpl::shared_state() const {
525   return reinterpret_cast<gpu::CommandBufferSharedState*>(
526       shared_state_shm_->memory());
527 }
528
529 void CommandBufferProxyImpl::OnSwapBuffersCompleted(
530     const std::vector<ui::LatencyInfo>& latency_info) {
531   if (!swap_buffers_completion_callback_.is_null()) {
532     if (!ui::LatencyInfo::Verify(
533             latency_info, "CommandBufferProxyImpl::OnSwapBuffersCompleted")) {
534       swap_buffers_completion_callback_.Run(std::vector<ui::LatencyInfo>());
535       return;
536     }
537     swap_buffers_completion_callback_.Run(latency_info);
538   }
539 }
540
541 }  // namespace content