ppapi_command_buffer_proxy.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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 "ppapi/proxy/ppapi_command_buffer_proxy.h"
6
7#include "ppapi/proxy/ppapi_messages.h"
8#include "ppapi/proxy/proxy_channel.h"
9#include "ppapi/shared_impl/api_id.h"
10#include "ppapi/shared_impl/host_resource.h"
11#include "ppapi/shared_impl/proxy_lock.h"
12
13namespace ppapi {
14namespace proxy {
15
16PpapiCommandBufferProxy::PpapiCommandBufferProxy(
17    const ppapi::HostResource& resource,
18    ProxyChannel* channel)
19    : resource_(resource),
20      channel_(channel) {
21}
22
23PpapiCommandBufferProxy::~PpapiCommandBufferProxy() {
24  // Delete all the locally cached shared memory objects, closing the handle
25  // in this process.
26  for (TransferBufferMap::iterator it = transfer_buffers_.begin();
27       it != transfer_buffers_.end(); ++it) {
28    delete it->second.shared_memory;
29    it->second.shared_memory = NULL;
30  }
31}
32
33bool PpapiCommandBufferProxy::Initialize() {
34  return true;
35}
36
37gpu::CommandBuffer::State PpapiCommandBufferProxy::GetState() {
38  // Send will flag state with lost context if IPC fails.
39  if (last_state_.error == gpu::error::kNoError) {
40    gpu::CommandBuffer::State state;
41    bool success = false;
42    if (Send(new PpapiHostMsg_PPBGraphics3D_GetState(
43             ppapi::API_ID_PPB_GRAPHICS_3D, resource_, &state, &success))) {
44      UpdateState(state, success);
45    }
46  }
47
48  return last_state_;
49}
50
51gpu::CommandBuffer::State PpapiCommandBufferProxy::GetLastState() {
52  ppapi::ProxyLock::AssertAcquiredDebugOnly();
53  return last_state_;
54}
55
56int32 PpapiCommandBufferProxy::GetLastToken() {
57  ppapi::ProxyLock::AssertAcquiredDebugOnly();
58  return last_state_.token;
59}
60
61void PpapiCommandBufferProxy::Flush(int32 put_offset) {
62  if (last_state_.error != gpu::error::kNoError)
63    return;
64
65  IPC::Message* message = new PpapiHostMsg_PPBGraphics3D_AsyncFlush(
66      ppapi::API_ID_PPB_GRAPHICS_3D, resource_, put_offset);
67
68  // Do not let a synchronous flush hold up this message. If this handler is
69  // deferred until after the synchronous flush completes, it will overwrite the
70  // cached last_state_ with out-of-date data.
71  message->set_unblock(true);
72  Send(message);
73}
74
75gpu::CommandBuffer::State PpapiCommandBufferProxy::FlushSync(int32 put_offset,
76                                                   int32 last_known_get) {
77  if (last_known_get == last_state_.get_offset) {
78    // Send will flag state with lost context if IPC fails.
79    if (last_state_.error == gpu::error::kNoError) {
80      gpu::CommandBuffer::State state;
81      bool success = false;
82      if (Send(new PpapiHostMsg_PPBGraphics3D_Flush(
83               ppapi::API_ID_PPB_GRAPHICS_3D, resource_, put_offset,
84              last_known_get, &state, &success))) {
85        UpdateState(state, success);
86      }
87    }
88  } else {
89    Flush(put_offset);
90  }
91  return last_state_;
92}
93
94void PpapiCommandBufferProxy::SetGetBuffer(int32 transfer_buffer_id) {
95  if (last_state_.error == gpu::error::kNoError) {
96    Send(new PpapiHostMsg_PPBGraphics3D_SetGetBuffer(
97         ppapi::API_ID_PPB_GRAPHICS_3D, resource_, transfer_buffer_id));
98  }
99}
100
101void PpapiCommandBufferProxy::SetGetOffset(int32 get_offset) {
102  // Not implemented in proxy.
103  NOTREACHED();
104}
105
106gpu::Buffer PpapiCommandBufferProxy::CreateTransferBuffer(size_t size,
107                                                          int32* id) {
108  *id = -1;
109
110  if (last_state_.error != gpu::error::kNoError)
111    return gpu::Buffer();
112
113  if (!Send(new PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer(
114            ppapi::API_ID_PPB_GRAPHICS_3D, resource_, size, id))) {
115    return gpu::Buffer();
116  }
117
118  if ((*id) <= 0)
119    return gpu::Buffer();
120
121  return GetTransferBuffer(*id);
122}
123
124void PpapiCommandBufferProxy::DestroyTransferBuffer(int32 id) {
125  if (last_state_.error != gpu::error::kNoError)
126    return;
127
128  // Remove the transfer buffer from the client side4 cache.
129  TransferBufferMap::iterator it = transfer_buffers_.find(id);
130
131  if (it != transfer_buffers_.end()) {
132    // Delete the shared memory object, closing the handle in this process.
133    delete it->second.shared_memory;
134
135    transfer_buffers_.erase(it);
136  }
137
138  Send(new PpapiHostMsg_PPBGraphics3D_DestroyTransferBuffer(
139      ppapi::API_ID_PPB_GRAPHICS_3D, resource_, id));
140}
141
142void PpapiCommandBufferProxy::Echo(const base::Closure& callback) {
143  NOTREACHED();
144}
145
146gpu::Buffer PpapiCommandBufferProxy::GetTransferBuffer(int32 id) {
147  if (last_state_.error != gpu::error::kNoError)
148    return gpu::Buffer();
149
150  // Check local cache to see if there is already a client side shared memory
151  // object for this id.
152  TransferBufferMap::iterator it = transfer_buffers_.find(id);
153  if (it != transfer_buffers_.end()) {
154    return it->second;
155  }
156
157  // Assuming we are in the renderer process, the service is responsible for
158  // duplicating the handle. This might not be true for NaCl.
159  ppapi::proxy::SerializedHandle handle(
160      ppapi::proxy::SerializedHandle::SHARED_MEMORY);
161  if (!Send(new PpapiHostMsg_PPBGraphics3D_GetTransferBuffer(
162            ppapi::API_ID_PPB_GRAPHICS_3D, resource_, id, &handle))) {
163    return gpu::Buffer();
164  }
165  if (!handle.is_shmem())
166    return gpu::Buffer();
167
168  // Cache the transfer buffer shared memory object client side.
169  scoped_ptr<base::SharedMemory> shared_memory(
170      new base::SharedMemory(handle.shmem(), false));
171
172  // Map the shared memory on demand.
173  if (!shared_memory->memory()) {
174    if (!shared_memory->Map(handle.size())) {
175      return gpu::Buffer();
176    }
177  }
178
179  gpu::Buffer buffer;
180  buffer.ptr = shared_memory->memory();
181  buffer.size = handle.size();
182  buffer.shared_memory = shared_memory.release();
183  transfer_buffers_[id] = buffer;
184
185  return buffer;
186}
187
188void PpapiCommandBufferProxy::SetToken(int32 token) {
189  NOTREACHED();
190}
191
192void PpapiCommandBufferProxy::SetParseError(gpu::error::Error error) {
193  NOTREACHED();
194}
195
196void PpapiCommandBufferProxy::SetContextLostReason(
197    gpu::error::ContextLostReason reason) {
198  NOTREACHED();
199}
200
201uint32 PpapiCommandBufferProxy::InsertSyncPoint() {
202  uint32 sync_point = 0;
203  if (last_state_.error == gpu::error::kNoError) {
204    Send(new PpapiHostMsg_PPBGraphics3D_InsertSyncPoint(
205         ppapi::API_ID_PPB_GRAPHICS_3D, resource_, &sync_point));
206  }
207  return sync_point;
208}
209
210void PpapiCommandBufferProxy::SignalSyncPoint(uint32 sync_point,
211                                              const base::Closure& callback) {
212  NOTREACHED();
213}
214
215void PpapiCommandBufferProxy::SignalQuery(uint32 query,
216                                          const base::Closure& callback) {
217  NOTREACHED();
218}
219
220void PpapiCommandBufferProxy::SetSurfaceVisible(bool visible) {
221  NOTREACHED();
222}
223
224void PpapiCommandBufferProxy::SendManagedMemoryStats(
225    const gpu::ManagedMemoryStats& stats) {
226  NOTREACHED();
227}
228
229gpu::Capabilities PpapiCommandBufferProxy::GetCapabilities() {
230  // TODO(boliu): Need to implement this to use cc in Pepper. Tracked in
231  // crbug.com/325391.
232  return gpu::Capabilities();
233}
234
235gfx::GpuMemoryBuffer* PpapiCommandBufferProxy::CreateGpuMemoryBuffer(
236    size_t width,
237    size_t height,
238    unsigned internalformat,
239    int32* id) {
240  NOTREACHED();
241  return NULL;
242}
243
244void PpapiCommandBufferProxy::DestroyGpuMemoryBuffer(int32 id) {
245  NOTREACHED();
246}
247
248bool PpapiCommandBufferProxy::GenerateMailboxNames(
249    unsigned num, std::vector<gpu::Mailbox>* names) {
250  // TODO(piman): implement this so we can expose mailboxes to pepper
251  // eventually.
252  NOTREACHED();
253  return false;
254}
255
256
257bool PpapiCommandBufferProxy::Send(IPC::Message* msg) {
258  DCHECK(last_state_.error == gpu::error::kNoError);
259
260  if (channel_->Send(msg))
261    return true;
262
263  last_state_.error = gpu::error::kLostContext;
264  return false;
265}
266
267void PpapiCommandBufferProxy::UpdateState(
268    const gpu::CommandBuffer::State& state,
269    bool success) {
270  // Handle wraparound. It works as long as we don't have more than 2B state
271  // updates in flight across which reordering occurs.
272  if (success) {
273    if (state.generation - last_state_.generation < 0x80000000U) {
274      last_state_ = state;
275    }
276  } else {
277    last_state_.error = gpu::error::kLostContext;
278    ++last_state_.generation;
279  }
280}
281
282}  // namespace proxy
283}  // namespace ppapi
284