ppapi_command_buffer_proxy.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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 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 32void PpapiCommandBufferProxy::ReportChannelError() { 33 if (!channel_error_callback_.is_null()) { 34 channel_error_callback_.Run(); 35 channel_error_callback_.Reset(); 36 } 37} 38 39int PpapiCommandBufferProxy::GetRouteID() const { 40 NOTIMPLEMENTED(); 41 return 0; 42} 43 44bool PpapiCommandBufferProxy::Echo(const base::Closure& callback) { 45 return false; 46} 47 48bool PpapiCommandBufferProxy::ProduceFrontBuffer(const gpu::Mailbox& mailbox) { 49 NOTIMPLEMENTED(); 50 return false; 51} 52 53void PpapiCommandBufferProxy::SetChannelErrorCallback( 54 const base::Closure& callback) { 55 channel_error_callback_ = callback; 56} 57 58bool PpapiCommandBufferProxy::Initialize() { 59 return true; 60} 61 62gpu::CommandBuffer::State PpapiCommandBufferProxy::GetState() { 63 // Send will flag state with lost context if IPC fails. 64 if (last_state_.error == gpu::error::kNoError) { 65 gpu::CommandBuffer::State state; 66 bool success = false; 67 if (Send(new PpapiHostMsg_PPBGraphics3D_GetState( 68 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, &state, &success))) { 69 UpdateState(state, success); 70 } 71 } 72 73 return last_state_; 74} 75 76gpu::CommandBuffer::State PpapiCommandBufferProxy::GetLastState() { 77 // Note: The locking command buffer wrapper does not take a global lock before 78 // calling this function. 79 return last_state_; 80} 81 82int32 PpapiCommandBufferProxy::GetLastToken() { 83 // Note: The locking command buffer wrapper does not take a global lock before 84 // calling this function. 85 return last_state_.token; 86} 87 88void PpapiCommandBufferProxy::Flush(int32 put_offset) { 89 if (last_state_.error != gpu::error::kNoError) 90 return; 91 92 IPC::Message* message = new PpapiHostMsg_PPBGraphics3D_AsyncFlush( 93 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, put_offset); 94 95 // Do not let a synchronous flush hold up this message. If this handler is 96 // deferred until after the synchronous flush completes, it will overwrite the 97 // cached last_state_ with out-of-date data. 98 message->set_unblock(true); 99 Send(message); 100} 101 102gpu::CommandBuffer::State PpapiCommandBufferProxy::FlushSync(int32 put_offset, 103 int32 last_known_get) { 104 if (last_known_get == last_state_.get_offset) { 105 // Send will flag state with lost context if IPC fails. 106 if (last_state_.error == gpu::error::kNoError) { 107 gpu::CommandBuffer::State state; 108 bool success = false; 109 if (Send(new PpapiHostMsg_PPBGraphics3D_Flush( 110 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, put_offset, 111 last_known_get, &state, &success))) { 112 UpdateState(state, success); 113 } 114 } 115 } else { 116 Flush(put_offset); 117 } 118 return last_state_; 119} 120 121void PpapiCommandBufferProxy::SetGetBuffer(int32 transfer_buffer_id) { 122 if (last_state_.error == gpu::error::kNoError) { 123 Send(new PpapiHostMsg_PPBGraphics3D_SetGetBuffer( 124 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, transfer_buffer_id)); 125 } 126} 127 128void PpapiCommandBufferProxy::SetGetOffset(int32 get_offset) { 129 // Not implemented in proxy. 130 NOTREACHED(); 131} 132 133gpu::Buffer PpapiCommandBufferProxy::CreateTransferBuffer(size_t size, 134 int32* id) { 135 *id = -1; 136 137 if (last_state_.error != gpu::error::kNoError) 138 return gpu::Buffer(); 139 140 if (!Send(new PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer( 141 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, size, id))) { 142 return gpu::Buffer(); 143 } 144 145 if ((*id) <= 0) 146 return gpu::Buffer(); 147 148 return GetTransferBuffer(*id); 149} 150 151void PpapiCommandBufferProxy::DestroyTransferBuffer(int32 id) { 152 if (last_state_.error != gpu::error::kNoError) 153 return; 154 155 // Remove the transfer buffer from the client side4 cache. 156 TransferBufferMap::iterator it = transfer_buffers_.find(id); 157 158 if (it != transfer_buffers_.end()) { 159 // Delete the shared memory object, closing the handle in this process. 160 delete it->second.shared_memory; 161 162 transfer_buffers_.erase(it); 163 } 164 165 Send(new PpapiHostMsg_PPBGraphics3D_DestroyTransferBuffer( 166 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, id)); 167} 168 169gpu::Buffer PpapiCommandBufferProxy::GetTransferBuffer(int32 id) { 170 if (last_state_.error != gpu::error::kNoError) 171 return gpu::Buffer(); 172 173 // Check local cache to see if there is already a client side shared memory 174 // object for this id. 175 TransferBufferMap::iterator it = transfer_buffers_.find(id); 176 if (it != transfer_buffers_.end()) { 177 return it->second; 178 } 179 180 // Assuming we are in the renderer process, the service is responsible for 181 // duplicating the handle. This might not be true for NaCl. 182 ppapi::proxy::SerializedHandle handle( 183 ppapi::proxy::SerializedHandle::SHARED_MEMORY); 184 if (!Send(new PpapiHostMsg_PPBGraphics3D_GetTransferBuffer( 185 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, id, &handle))) { 186 return gpu::Buffer(); 187 } 188 if (!handle.is_shmem()) 189 return gpu::Buffer(); 190 191 // Cache the transfer buffer shared memory object client side. 192 scoped_ptr<base::SharedMemory> shared_memory( 193 new base::SharedMemory(handle.shmem(), false)); 194 195 // Map the shared memory on demand. 196 if (!shared_memory->memory()) { 197 if (!shared_memory->Map(handle.size())) { 198 return gpu::Buffer(); 199 } 200 } 201 202 gpu::Buffer buffer; 203 buffer.ptr = shared_memory->memory(); 204 buffer.size = handle.size(); 205 buffer.shared_memory = shared_memory.release(); 206 transfer_buffers_[id] = buffer; 207 208 return buffer; 209} 210 211void PpapiCommandBufferProxy::SetToken(int32 token) { 212 NOTREACHED(); 213} 214 215void PpapiCommandBufferProxy::SetParseError(gpu::error::Error error) { 216 NOTREACHED(); 217} 218 219void PpapiCommandBufferProxy::SetContextLostReason( 220 gpu::error::ContextLostReason reason) { 221 NOTREACHED(); 222} 223 224uint32 PpapiCommandBufferProxy::InsertSyncPoint() { 225 uint32 sync_point = 0; 226 if (last_state_.error == gpu::error::kNoError) { 227 Send(new PpapiHostMsg_PPBGraphics3D_InsertSyncPoint( 228 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, &sync_point)); 229 } 230 return sync_point; 231} 232 233bool PpapiCommandBufferProxy::Send(IPC::Message* msg) { 234 DCHECK(last_state_.error == gpu::error::kNoError); 235 236 if (channel_->Send(msg)) 237 return true; 238 239 last_state_.error = gpu::error::kLostContext; 240 return false; 241} 242 243void PpapiCommandBufferProxy::UpdateState( 244 const gpu::CommandBuffer::State& state, 245 bool success) { 246 // Handle wraparound. It works as long as we don't have more than 2B state 247 // updates in flight across which reordering occurs. 248 if (success) { 249 if (state.generation - last_state_.generation < 0x80000000U) { 250 last_state_ = state; 251 } 252 } else { 253 last_state_.error = gpu::error::kLostContext; 254 ++last_state_.generation; 255 } 256} 257 258} // namespace proxy 259} // namespace ppapi 260