blob: 98c235357e472b526e08cd416a3e424ec81bec5d [file] [log] [blame]
[email protected]aaa11b32012-03-08 12:30:131// 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
12namespace ppapi {
13namespace proxy {
14
15PpapiCommandBufferProxy::PpapiCommandBufferProxy(
16 const ppapi::HostResource& resource,
17 ProxyChannel* channel)
18 : resource_(resource),
19 channel_(channel) {
20}
21
22PpapiCommandBufferProxy::~PpapiCommandBufferProxy() {
23 // Delete all the locally cached shared memory objects, closing the handle
24 // in this process.
25 for (TransferBufferMap::iterator it = transfer_buffers_.begin();
26 it != transfer_buffers_.end(); ++it) {
27 delete it->second.shared_memory;
28 it->second.shared_memory = NULL;
29 }
30}
31
[email protected]2651ef6e2012-03-28 23:47:2732void PpapiCommandBufferProxy::ReportChannelError() {
33 if (!channel_error_callback_.is_null()) {
34 channel_error_callback_.Run();
35 channel_error_callback_.Reset();
36 }
37}
38
[email protected]9e5fffaf2012-04-02 23:32:3739int PpapiCommandBufferProxy::GetRouteID() const {
40 NOTIMPLEMENTED();
41 return 0;
42}
43
44bool PpapiCommandBufferProxy::Echo(const base::Closure& callback) {
[email protected]9e5fffaf2012-04-02 23:32:3745 return false;
46}
47
[email protected]9e5fffaf2012-04-02 23:32:3748bool PpapiCommandBufferProxy::SetParent(
49 CommandBufferProxy* parent_command_buffer,
50 uint32 parent_texture_id) {
51 // TODO(fsamuel): Need a proper implementation of this to support offscreen
52 // contexts in the guest renderer (WebGL, canvas, etc).
53 NOTIMPLEMENTED();
54 return false;
55}
56
57void PpapiCommandBufferProxy::SetChannelErrorCallback(
58 const base::Closure& callback) {
59 channel_error_callback_ = callback;
60}
61
[email protected]aaa11b32012-03-08 12:30:1362bool PpapiCommandBufferProxy::Initialize() {
63 return Send(new PpapiHostMsg_PPBGraphics3D_InitCommandBuffer(
64 ppapi::API_ID_PPB_GRAPHICS_3D, resource_));
65}
66
67gpu::CommandBuffer::State PpapiCommandBufferProxy::GetState() {
68 // Send will flag state with lost context if IPC fails.
69 if (last_state_.error == gpu::error::kNoError) {
70 gpu::CommandBuffer::State state;
[email protected]571b35e82012-05-19 00:04:3571 bool success = false;
[email protected]aaa11b32012-03-08 12:30:1372 if (Send(new PpapiHostMsg_PPBGraphics3D_GetState(
[email protected]571b35e82012-05-19 00:04:3573 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, &state, &success))) {
74 UpdateState(state, success);
[email protected]aaa11b32012-03-08 12:30:1375 }
76 }
77
78 return last_state_;
79}
80
81gpu::CommandBuffer::State PpapiCommandBufferProxy::GetLastState() {
[email protected]84b44c552012-10-15 20:58:1782 // Note: The locking command buffer wrapper does not take a global lock before
83 // calling this function.
[email protected]aaa11b32012-03-08 12:30:1384 return last_state_;
85}
86
[email protected]a597c622013-01-25 05:08:3887int32 PpapiCommandBufferProxy::GetLastToken() {
88 // Note: The locking command buffer wrapper does not take a global lock before
89 // calling this function.
90 return last_state_.token;
91}
92
[email protected]aaa11b32012-03-08 12:30:1393void PpapiCommandBufferProxy::Flush(int32 put_offset) {
94 if (last_state_.error != gpu::error::kNoError)
95 return;
96
97 IPC::Message* message = new PpapiHostMsg_PPBGraphics3D_AsyncFlush(
98 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, put_offset);
99
100 // Do not let a synchronous flush hold up this message. If this handler is
101 // deferred until after the synchronous flush completes, it will overwrite the
102 // cached last_state_ with out-of-date data.
103 message->set_unblock(true);
104 Send(message);
105}
106
107gpu::CommandBuffer::State PpapiCommandBufferProxy::FlushSync(int32 put_offset,
108 int32 last_known_get) {
109 if (last_known_get == last_state_.get_offset) {
110 // Send will flag state with lost context if IPC fails.
111 if (last_state_.error == gpu::error::kNoError) {
112 gpu::CommandBuffer::State state;
[email protected]571b35e82012-05-19 00:04:35113 bool success = false;
[email protected]aaa11b32012-03-08 12:30:13114 if (Send(new PpapiHostMsg_PPBGraphics3D_Flush(
115 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, put_offset,
[email protected]571b35e82012-05-19 00:04:35116 last_known_get, &state, &success))) {
117 UpdateState(state, success);
[email protected]aaa11b32012-03-08 12:30:13118 }
119 }
120 } else {
121 Flush(put_offset);
122 }
123 return last_state_;
124}
125
126void PpapiCommandBufferProxy::SetGetBuffer(int32 transfer_buffer_id) {
127 if (last_state_.error == gpu::error::kNoError) {
128 Send(new PpapiHostMsg_PPBGraphics3D_SetGetBuffer(
129 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, transfer_buffer_id));
130 }
131}
132
133void PpapiCommandBufferProxy::SetGetOffset(int32 get_offset) {
134 // Not implemented in proxy.
135 NOTREACHED();
136}
137
[email protected]67c80782012-12-21 01:16:52138gpu::Buffer PpapiCommandBufferProxy::CreateTransferBuffer(size_t size,
139 int32* id) {
140 *id = -1;
[email protected]9cef7702012-12-13 03:33:59141
[email protected]67c80782012-12-21 01:16:52142 if (last_state_.error != gpu::error::kNoError)
143 return gpu::Buffer();
144
145 if (!Send(new PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer(
146 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, size, id))) {
147 return gpu::Buffer();
148 }
149
150 if ((*id) <= 0)
151 return gpu::Buffer();
152
153 return GetTransferBuffer(*id);
[email protected]aaa11b32012-03-08 12:30:13154}
155
156void PpapiCommandBufferProxy::DestroyTransferBuffer(int32 id) {
157 if (last_state_.error != gpu::error::kNoError)
158 return;
159
160 // Remove the transfer buffer from the client side4 cache.
161 TransferBufferMap::iterator it = transfer_buffers_.find(id);
[email protected]aaa11b32012-03-08 12:30:13162
[email protected]852ab722012-10-25 21:08:25163 if (it != transfer_buffers_.end()) {
164 // Delete the shared memory object, closing the handle in this process.
165 delete it->second.shared_memory;
[email protected]aaa11b32012-03-08 12:30:13166
[email protected]852ab722012-10-25 21:08:25167 transfer_buffers_.erase(it);
168 }
[email protected]aaa11b32012-03-08 12:30:13169
170 Send(new PpapiHostMsg_PPBGraphics3D_DestroyTransferBuffer(
171 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, id));
172}
173
174gpu::Buffer PpapiCommandBufferProxy::GetTransferBuffer(int32 id) {
175 if (last_state_.error != gpu::error::kNoError)
176 return gpu::Buffer();
177
178 // Check local cache to see if there is already a client side shared memory
179 // object for this id.
180 TransferBufferMap::iterator it = transfer_buffers_.find(id);
181 if (it != transfer_buffers_.end()) {
182 return it->second;
183 }
184
185 // Assuming we are in the renderer process, the service is responsible for
186 // duplicating the handle. This might not be true for NaCl.
[email protected]246fc492012-08-27 20:28:18187 ppapi::proxy::SerializedHandle handle(
188 ppapi::proxy::SerializedHandle::SHARED_MEMORY);
[email protected]aaa11b32012-03-08 12:30:13189 if (!Send(new PpapiHostMsg_PPBGraphics3D_GetTransferBuffer(
[email protected]246fc492012-08-27 20:28:18190 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, id, &handle))) {
[email protected]aaa11b32012-03-08 12:30:13191 return gpu::Buffer();
192 }
[email protected]246fc492012-08-27 20:28:18193 if (!handle.is_shmem())
194 return gpu::Buffer();
[email protected]aaa11b32012-03-08 12:30:13195
196 // Cache the transfer buffer shared memory object client side.
197 scoped_ptr<base::SharedMemory> shared_memory(
[email protected]246fc492012-08-27 20:28:18198 new base::SharedMemory(handle.shmem(), false));
[email protected]aaa11b32012-03-08 12:30:13199
200 // Map the shared memory on demand.
201 if (!shared_memory->memory()) {
[email protected]246fc492012-08-27 20:28:18202 if (!shared_memory->Map(handle.size())) {
[email protected]aaa11b32012-03-08 12:30:13203 return gpu::Buffer();
204 }
205 }
206
207 gpu::Buffer buffer;
208 buffer.ptr = shared_memory->memory();
[email protected]246fc492012-08-27 20:28:18209 buffer.size = handle.size();
[email protected]aaa11b32012-03-08 12:30:13210 buffer.shared_memory = shared_memory.release();
211 transfer_buffers_[id] = buffer;
212
213 return buffer;
214}
215
216void PpapiCommandBufferProxy::SetToken(int32 token) {
217 NOTREACHED();
218}
219
220void PpapiCommandBufferProxy::SetParseError(gpu::error::Error error) {
221 NOTREACHED();
222}
223
224void PpapiCommandBufferProxy::SetContextLostReason(
225 gpu::error::ContextLostReason reason) {
226 NOTREACHED();
227}
228
[email protected]b096d032013-03-08 03:08:01229uint32 PpapiCommandBufferProxy::InsertSyncPoint() {
230 uint32 sync_point = 0;
231 if (last_state_.error == gpu::error::kNoError) {
232 Send(new PpapiHostMsg_PPBGraphics3D_InsertSyncPoint(
233 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, &sync_point));
234 }
235 return sync_point;
236}
237
[email protected]aaa11b32012-03-08 12:30:13238bool PpapiCommandBufferProxy::Send(IPC::Message* msg) {
239 DCHECK(last_state_.error == gpu::error::kNoError);
240
241 if (channel_->Send(msg))
242 return true;
243
244 last_state_.error = gpu::error::kLostContext;
245 return false;
246}
247
248void PpapiCommandBufferProxy::UpdateState(
[email protected]571b35e82012-05-19 00:04:35249 const gpu::CommandBuffer::State& state,
250 bool success) {
[email protected]aaa11b32012-03-08 12:30:13251 // Handle wraparound. It works as long as we don't have more than 2B state
252 // updates in flight across which reordering occurs.
[email protected]571b35e82012-05-19 00:04:35253 if (success) {
254 if (state.generation - last_state_.generation < 0x80000000U) {
255 last_state_ = state;
[email protected]b44a9862012-05-22 22:08:43256 }
257 } else {
[email protected]571b35e82012-05-19 00:04:35258 last_state_.error = gpu::error::kLostContext;
259 ++last_state_.generation;
260 }
[email protected]aaa11b32012-03-08 12:30:13261}
262
263} // namespace proxy
264} // namespace ppapi