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 gpu::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 188 void PpapiCommandBufferProxy::SetToken(int32 token) { 189 NOTREACHED(); 190 } 191 192 void PpapiCommandBufferProxy::SetParseError(gpu::error::Error error) { 193 NOTREACHED(); 194 } 195 196 void PpapiCommandBufferProxy::SetContextLostReason( 197 gpu::error::ContextLostReason reason) { 198 NOTREACHED(); 199 } 200 201 uint32 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 210 void PpapiCommandBufferProxy::SignalSyncPoint(uint32 sync_point, 211 const base::Closure& callback) { 212 NOTREACHED(); 213 } 214 215 void PpapiCommandBufferProxy::SignalQuery(uint32 query, 216 const base::Closure& callback) { 217 NOTREACHED(); 218 } 219 220 void PpapiCommandBufferProxy::SetSurfaceVisible(bool visible) { 221 NOTREACHED(); 222 } 223 224 void PpapiCommandBufferProxy::SendManagedMemoryStats( 225 const gpu::ManagedMemoryStats& stats) { 226 NOTREACHED(); 227 } 228 229 gpu::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 235 gfx::GpuMemoryBuffer* PpapiCommandBufferProxy::CreateGpuMemoryBuffer( 236 size_t width, 237 size_t height, 238 unsigned internalformat, 239 int32* id) { 240 NOTREACHED(); 241 return NULL; 242 } 243 244 void PpapiCommandBufferProxy::DestroyGpuMemoryBuffer(int32 id) { 245 NOTREACHED(); 246 } 247 248 bool 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 257 bool 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 267 void 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