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.
5 #include "ppapi/proxy/ppapi_command_buffer_proxy.h"
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"
15 PpapiCommandBufferProxy::PpapiCommandBufferProxy(
16 const ppapi::HostResource
& resource
,
17 ProxyChannel
* channel
)
18 : resource_(resource
),
22 PpapiCommandBufferProxy::~PpapiCommandBufferProxy() {
23 // Delete all the locally cached shared memory objects, closing the handle
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
;
32 void PpapiCommandBufferProxy::ReportChannelError() {
33 if (!channel_error_callback_
.is_null()) {
34 channel_error_callback_
.Run();
35 channel_error_callback_
.Reset();
39 int PpapiCommandBufferProxy::GetRouteID() const {
44 bool PpapiCommandBufferProxy::Echo(const base::Closure
& callback
) {
48 bool PpapiCommandBufferProxy::SetSurfaceVisible(bool visible
) {
53 bool PpapiCommandBufferProxy::DiscardBackbuffer() {
58 bool PpapiCommandBufferProxy::EnsureBackbuffer() {
63 uint32
PpapiCommandBufferProxy::InsertSyncPoint() {
68 void PpapiCommandBufferProxy::WaitSyncPoint(uint32 sync_point
) {
72 bool PpapiCommandBufferProxy::SignalSyncPoint(uint32 sync_point
,
73 const base::Closure
& callback
) {
78 void PpapiCommandBufferProxy::SetMemoryAllocationChangedCallback(
79 const base::Callback
<void(const GpuMemoryAllocationForRenderer
&)>&
84 bool PpapiCommandBufferProxy::SetParent(
85 CommandBufferProxy
* parent_command_buffer
,
86 uint32 parent_texture_id
) {
87 // TODO(fsamuel): Need a proper implementation of this to support offscreen
88 // contexts in the guest renderer (WebGL, canvas, etc).
93 void PpapiCommandBufferProxy::SetChannelErrorCallback(
94 const base::Closure
& callback
) {
95 channel_error_callback_
= callback
;
98 void PpapiCommandBufferProxy::SetNotifyRepaintTask(
99 const base::Closure
& callback
) {
103 void PpapiCommandBufferProxy::SetOnConsoleMessageCallback(
104 const GpuConsoleMessageCallback
& callback
) {
108 bool PpapiCommandBufferProxy::Initialize() {
109 return Send(new PpapiHostMsg_PPBGraphics3D_InitCommandBuffer(
110 ppapi::API_ID_PPB_GRAPHICS_3D
, resource_
));
113 gpu::CommandBuffer::State
PpapiCommandBufferProxy::GetState() {
114 // Send will flag state with lost context if IPC fails.
115 if (last_state_
.error
== gpu::error::kNoError
) {
116 gpu::CommandBuffer::State state
;
117 bool success
= false;
118 if (Send(new PpapiHostMsg_PPBGraphics3D_GetState(
119 ppapi::API_ID_PPB_GRAPHICS_3D
, resource_
, &state
, &success
))) {
120 UpdateState(state
, success
);
127 gpu::CommandBuffer::State
PpapiCommandBufferProxy::GetLastState() {
131 void PpapiCommandBufferProxy::Flush(int32 put_offset
) {
132 if (last_state_
.error
!= gpu::error::kNoError
)
135 IPC::Message
* message
= new PpapiHostMsg_PPBGraphics3D_AsyncFlush(
136 ppapi::API_ID_PPB_GRAPHICS_3D
, resource_
, put_offset
);
138 // Do not let a synchronous flush hold up this message. If this handler is
139 // deferred until after the synchronous flush completes, it will overwrite the
140 // cached last_state_ with out-of-date data.
141 message
->set_unblock(true);
145 gpu::CommandBuffer::State
PpapiCommandBufferProxy::FlushSync(int32 put_offset
,
146 int32 last_known_get
) {
147 if (last_known_get
== last_state_
.get_offset
) {
148 // Send will flag state with lost context if IPC fails.
149 if (last_state_
.error
== gpu::error::kNoError
) {
150 gpu::CommandBuffer::State state
;
151 bool success
= false;
152 if (Send(new PpapiHostMsg_PPBGraphics3D_Flush(
153 ppapi::API_ID_PPB_GRAPHICS_3D
, resource_
, put_offset
,
154 last_known_get
, &state
, &success
))) {
155 UpdateState(state
, success
);
164 void PpapiCommandBufferProxy::SetGetBuffer(int32 transfer_buffer_id
) {
165 if (last_state_
.error
== gpu::error::kNoError
) {
166 Send(new PpapiHostMsg_PPBGraphics3D_SetGetBuffer(
167 ppapi::API_ID_PPB_GRAPHICS_3D
, resource_
, transfer_buffer_id
));
171 void PpapiCommandBufferProxy::SetGetOffset(int32 get_offset
) {
172 // Not implemented in proxy.
176 int32
PpapiCommandBufferProxy::CreateTransferBuffer(
179 if (last_state_
.error
== gpu::error::kNoError
) {
181 if (Send(new PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer(
182 ppapi::API_ID_PPB_GRAPHICS_3D
, resource_
, size
, &id
))) {
189 int32
PpapiCommandBufferProxy::RegisterTransferBuffer(
190 base::SharedMemory
* shared_memory
,
193 // Not implemented in proxy.
198 void PpapiCommandBufferProxy::DestroyTransferBuffer(int32 id
) {
199 if (last_state_
.error
!= gpu::error::kNoError
)
202 // Remove the transfer buffer from the client side4 cache.
203 TransferBufferMap::iterator it
= transfer_buffers_
.find(id
);
204 DCHECK(it
!= transfer_buffers_
.end());
206 // Delete the shared memory object, closing the handle in this process.
207 delete it
->second
.shared_memory
;
209 transfer_buffers_
.erase(it
);
211 Send(new PpapiHostMsg_PPBGraphics3D_DestroyTransferBuffer(
212 ppapi::API_ID_PPB_GRAPHICS_3D
, resource_
, id
));
215 gpu::Buffer
PpapiCommandBufferProxy::GetTransferBuffer(int32 id
) {
216 if (last_state_
.error
!= gpu::error::kNoError
)
217 return gpu::Buffer();
219 // Check local cache to see if there is already a client side shared memory
220 // object for this id.
221 TransferBufferMap::iterator it
= transfer_buffers_
.find(id
);
222 if (it
!= transfer_buffers_
.end()) {
226 // Assuming we are in the renderer process, the service is responsible for
227 // duplicating the handle. This might not be true for NaCl.
228 base::SharedMemoryHandle handle
;
230 if (!Send(new PpapiHostMsg_PPBGraphics3D_GetTransferBuffer(
231 ppapi::API_ID_PPB_GRAPHICS_3D
, resource_
, id
, &handle
, &size
))) {
232 return gpu::Buffer();
235 // Cache the transfer buffer shared memory object client side.
236 scoped_ptr
<base::SharedMemory
> shared_memory(
237 new base::SharedMemory(handle
, false));
239 // Map the shared memory on demand.
240 if (!shared_memory
->memory()) {
241 if (!shared_memory
->Map(size
)) {
242 return gpu::Buffer();
247 buffer
.ptr
= shared_memory
->memory();
249 buffer
.shared_memory
= shared_memory
.release();
250 transfer_buffers_
[id
] = buffer
;
255 void PpapiCommandBufferProxy::SetToken(int32 token
) {
259 void PpapiCommandBufferProxy::SetParseError(gpu::error::Error error
) {
263 void PpapiCommandBufferProxy::SetContextLostReason(
264 gpu::error::ContextLostReason reason
) {
268 bool PpapiCommandBufferProxy::Send(IPC::Message
* msg
) {
269 DCHECK(last_state_
.error
== gpu::error::kNoError
);
271 if (channel_
->Send(msg
))
274 last_state_
.error
= gpu::error::kLostContext
;
278 void PpapiCommandBufferProxy::UpdateState(
279 const gpu::CommandBuffer::State
& state
,
281 // Handle wraparound. It works as long as we don't have more than 2B state
282 // updates in flight across which reordering occurs.
284 if (state
.generation
- last_state_
.generation
< 0x80000000U
) {
288 last_state_
.error
= gpu::error::kLostContext
;
289 ++last_state_
.generation
;