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