c2f74e278b878df9182100c0a096cd58261989f6
[platform/framework/web/crosswalk.git] / src / ppapi / proxy / ppapi_command_buffer_proxy.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 "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
13 namespace ppapi {
14 namespace proxy {
15
16 PpapiCommandBufferProxy::PpapiCommandBufferProxy(
17     const ppapi::HostResource& resource,
18     ProxyChannel* channel)
19     : resource_(resource),
20       channel_(channel) {
21 }
22
23 PpapiCommandBufferProxy::~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
33 bool PpapiCommandBufferProxy::Initialize() {
34   return true;
35 }
36
37 gpu::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
51 gpu::CommandBuffer::State PpapiCommandBufferProxy::GetLastState() {
52   ppapi::ProxyLock::AssertAcquiredDebugOnly();
53   return last_state_;
54 }
55
56 int32 PpapiCommandBufferProxy::GetLastToken() {
57   ppapi::ProxyLock::AssertAcquiredDebugOnly();
58   return last_state_.token;
59 }
60
61 void 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
75 gpu::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
94 void 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
101 void PpapiCommandBufferProxy::SetGetOffset(int32 get_offset) {
102   // Not implemented in proxy.
103   NOTREACHED();
104 }
105
106 gpu::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
124 void 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
142 void PpapiCommandBufferProxy::Echo(const base::Closure& callback) {
143   NOTREACHED();
144 }
145
146 uint32 PpapiCommandBufferProxy::CreateStreamTexture(uint32 texture_id) {
147   NOTREACHED();
148   return 0;
149 }
150
151 gpu::Buffer PpapiCommandBufferProxy::GetTransferBuffer(int32 id) {
152   if (last_state_.error != gpu::error::kNoError)
153     return gpu::Buffer();
154
155   // Check local cache to see if there is already a client side shared memory
156   // object for this id.
157   TransferBufferMap::iterator it = transfer_buffers_.find(id);
158   if (it != transfer_buffers_.end()) {
159     return it->second;
160   }
161
162   // Assuming we are in the renderer process, the service is responsible for
163   // duplicating the handle. This might not be true for NaCl.
164   ppapi::proxy::SerializedHandle handle(
165       ppapi::proxy::SerializedHandle::SHARED_MEMORY);
166   if (!Send(new PpapiHostMsg_PPBGraphics3D_GetTransferBuffer(
167             ppapi::API_ID_PPB_GRAPHICS_3D, resource_, id, &handle))) {
168     return gpu::Buffer();
169   }
170   if (!handle.is_shmem())
171     return gpu::Buffer();
172
173   // Cache the transfer buffer shared memory object client side.
174   scoped_ptr<base::SharedMemory> shared_memory(
175       new base::SharedMemory(handle.shmem(), false));
176
177   // Map the shared memory on demand.
178   if (!shared_memory->memory()) {
179     if (!shared_memory->Map(handle.size())) {
180       return gpu::Buffer();
181     }
182   }
183
184   gpu::Buffer buffer;
185   buffer.ptr = shared_memory->memory();
186   buffer.size = handle.size();
187   buffer.shared_memory = shared_memory.release();
188   transfer_buffers_[id] = buffer;
189
190   return buffer;
191 }
192
193 void PpapiCommandBufferProxy::SetToken(int32 token) {
194   NOTREACHED();
195 }
196
197 void PpapiCommandBufferProxy::SetParseError(gpu::error::Error error) {
198   NOTREACHED();
199 }
200
201 void PpapiCommandBufferProxy::SetContextLostReason(
202     gpu::error::ContextLostReason reason) {
203   NOTREACHED();
204 }
205
206 uint32 PpapiCommandBufferProxy::InsertSyncPoint() {
207   uint32 sync_point = 0;
208   if (last_state_.error == gpu::error::kNoError) {
209     Send(new PpapiHostMsg_PPBGraphics3D_InsertSyncPoint(
210          ppapi::API_ID_PPB_GRAPHICS_3D, resource_, &sync_point));
211   }
212   return sync_point;
213 }
214
215 void PpapiCommandBufferProxy::SignalSyncPoint(uint32 sync_point,
216                                               const base::Closure& callback) {
217   NOTREACHED();
218 }
219
220 void PpapiCommandBufferProxy::SignalQuery(uint32 query,
221                                           const base::Closure& callback) {
222   NOTREACHED();
223 }
224
225 void PpapiCommandBufferProxy::SetSurfaceVisible(bool visible) {
226   NOTREACHED();
227 }
228
229 void PpapiCommandBufferProxy::SendManagedMemoryStats(
230     const gpu::ManagedMemoryStats& stats) {
231   NOTREACHED();
232 }
233
234 gpu::Capabilities PpapiCommandBufferProxy::GetCapabilities() {
235   // TODO(boliu): Need to implement this to use cc in Pepper. Tracked in
236   // crbug.com/325391.
237   return gpu::Capabilities();
238 }
239
240 gfx::GpuMemoryBuffer* PpapiCommandBufferProxy::CreateGpuMemoryBuffer(
241     size_t width,
242     size_t height,
243     unsigned internalformat,
244     int32* id) {
245   NOTREACHED();
246   return NULL;
247 }
248
249 void PpapiCommandBufferProxy::DestroyGpuMemoryBuffer(int32 id) {
250   NOTREACHED();
251 }
252
253 bool PpapiCommandBufferProxy::GenerateMailboxNames(
254     unsigned num, std::vector<gpu::Mailbox>* names) {
255   // TODO(piman): implement this so we can expose mailboxes to pepper
256   // eventually.
257   NOTREACHED();
258   return false;
259 }
260
261
262 bool PpapiCommandBufferProxy::Send(IPC::Message* msg) {
263   DCHECK(last_state_.error == gpu::error::kNoError);
264
265   if (channel_->Send(msg))
266     return true;
267
268   last_state_.error = gpu::error::kLostContext;
269   return false;
270 }
271
272 void PpapiCommandBufferProxy::UpdateState(
273     const gpu::CommandBuffer::State& state,
274     bool success) {
275   // Handle wraparound. It works as long as we don't have more than 2B state
276   // updates in flight across which reordering occurs.
277   if (success) {
278     if (state.generation - last_state_.generation < 0x80000000U) {
279       last_state_ = state;
280     }
281   } else {
282     last_state_.error = gpu::error::kLostContext;
283     ++last_state_.generation;
284   }
285 }
286
287 }  // namespace proxy
288 }  // namespace ppapi