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 const SerializedHandle& shared_state) 20 : resource_(resource), 21 channel_(channel) { 22 shared_state_shm_.reset( 23 new base::SharedMemory(shared_state.shmem(), false)); 24 shared_state_shm_->Map(shared_state.size()); 25} 26 27PpapiCommandBufferProxy::~PpapiCommandBufferProxy() { 28 // gpu::Buffers are no longer referenced, allowing shared memory objects to be 29 // deleted, closing the handle in this process. 30} 31 32bool PpapiCommandBufferProxy::Initialize() { 33 return true; 34} 35 36gpu::CommandBuffer::State PpapiCommandBufferProxy::GetLastState() { 37 ppapi::ProxyLock::AssertAcquiredDebugOnly(); 38 return last_state_; 39} 40 41int32 PpapiCommandBufferProxy::GetLastToken() { 42 ppapi::ProxyLock::AssertAcquiredDebugOnly(); 43 TryUpdateState(); 44 return last_state_.token; 45} 46 47void PpapiCommandBufferProxy::Flush(int32 put_offset) { 48 if (last_state_.error != gpu::error::kNoError) 49 return; 50 51 IPC::Message* message = new PpapiHostMsg_PPBGraphics3D_AsyncFlush( 52 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, put_offset); 53 54 // Do not let a synchronous flush hold up this message. If this handler is 55 // deferred until after the synchronous flush completes, it will overwrite the 56 // cached last_state_ with out-of-date data. 57 message->set_unblock(true); 58 Send(message); 59} 60 61void PpapiCommandBufferProxy::WaitForTokenInRange(int32 start, int32 end) { 62 TryUpdateState(); 63 if (!InRange(start, end, last_state_.token) && 64 last_state_.error == gpu::error::kNoError) { 65 bool success = false; 66 gpu::CommandBuffer::State state; 67 if (Send(new PpapiHostMsg_PPBGraphics3D_WaitForTokenInRange( 68 ppapi::API_ID_PPB_GRAPHICS_3D, 69 resource_, 70 start, 71 end, 72 &state, 73 &success))) 74 UpdateState(state, success); 75 } 76 DCHECK(InRange(start, end, last_state_.token) || 77 last_state_.error != gpu::error::kNoError); 78} 79 80void PpapiCommandBufferProxy::WaitForGetOffsetInRange(int32 start, int32 end) { 81 TryUpdateState(); 82 if (!InRange(start, end, last_state_.get_offset) && 83 last_state_.error == gpu::error::kNoError) { 84 bool success = false; 85 gpu::CommandBuffer::State state; 86 if (Send(new PpapiHostMsg_PPBGraphics3D_WaitForGetOffsetInRange( 87 ppapi::API_ID_PPB_GRAPHICS_3D, 88 resource_, 89 start, 90 end, 91 &state, 92 &success))) 93 UpdateState(state, success); 94 } 95 DCHECK(InRange(start, end, last_state_.get_offset) || 96 last_state_.error != gpu::error::kNoError); 97} 98 99void PpapiCommandBufferProxy::SetGetBuffer(int32 transfer_buffer_id) { 100 if (last_state_.error == gpu::error::kNoError) { 101 Send(new PpapiHostMsg_PPBGraphics3D_SetGetBuffer( 102 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, transfer_buffer_id)); 103 } 104} 105 106scoped_refptr<gpu::Buffer> PpapiCommandBufferProxy::CreateTransferBuffer( 107 size_t size, 108 int32* id) { 109 *id = -1; 110 111 if (last_state_.error != gpu::error::kNoError) 112 return NULL; 113 114 // Assuming we are in the renderer process, the service is responsible for 115 // duplicating the handle. This might not be true for NaCl. 116 ppapi::proxy::SerializedHandle handle( 117 ppapi::proxy::SerializedHandle::SHARED_MEMORY); 118 if (!Send(new PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer( 119 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, size, id, &handle))) { 120 return NULL; 121 } 122 123 if (*id <= 0 || !handle.is_shmem()) 124 return NULL; 125 126 scoped_ptr<base::SharedMemory> shared_memory( 127 new base::SharedMemory(handle.shmem(), false)); 128 129 // Map the shared memory on demand. 130 if (!shared_memory->memory()) { 131 if (!shared_memory->Map(handle.size())) { 132 *id = -1; 133 return NULL; 134 } 135 } 136 137 return gpu::MakeBufferFromSharedMemory(shared_memory.Pass(), handle.size()); 138} 139 140void PpapiCommandBufferProxy::DestroyTransferBuffer(int32 id) { 141 if (last_state_.error != gpu::error::kNoError) 142 return; 143 144 Send(new PpapiHostMsg_PPBGraphics3D_DestroyTransferBuffer( 145 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, id)); 146} 147 148void PpapiCommandBufferProxy::Echo(const base::Closure& callback) { 149 NOTREACHED(); 150} 151 152uint32 PpapiCommandBufferProxy::CreateStreamTexture(uint32 texture_id) { 153 NOTREACHED(); 154 return 0; 155} 156 157uint32 PpapiCommandBufferProxy::InsertSyncPoint() { 158 uint32 sync_point = 0; 159 if (last_state_.error == gpu::error::kNoError) { 160 Send(new PpapiHostMsg_PPBGraphics3D_InsertSyncPoint( 161 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, &sync_point)); 162 } 163 return sync_point; 164} 165 166uint32 PpapiCommandBufferProxy::InsertFutureSyncPoint() { 167 uint32 sync_point = 0; 168 if (last_state_.error == gpu::error::kNoError) { 169 Send(new PpapiHostMsg_PPBGraphics3D_InsertFutureSyncPoint( 170 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, &sync_point)); 171 } 172 return sync_point; 173} 174 175void PpapiCommandBufferProxy::RetireSyncPoint(uint32 sync_point) { 176 if (last_state_.error == gpu::error::kNoError) { 177 Send(new PpapiHostMsg_PPBGraphics3D_RetireSyncPoint( 178 ppapi::API_ID_PPB_GRAPHICS_3D, resource_, sync_point)); 179 } 180} 181 182void PpapiCommandBufferProxy::SignalSyncPoint(uint32 sync_point, 183 const base::Closure& callback) { 184 NOTREACHED(); 185} 186 187void PpapiCommandBufferProxy::SignalQuery(uint32 query, 188 const base::Closure& callback) { 189 NOTREACHED(); 190} 191 192void PpapiCommandBufferProxy::SetSurfaceVisible(bool visible) { 193 NOTREACHED(); 194} 195 196gpu::Capabilities PpapiCommandBufferProxy::GetCapabilities() { 197 // TODO(boliu): Need to implement this to use cc in Pepper. Tracked in 198 // crbug.com/325391. 199 return gpu::Capabilities(); 200} 201 202gfx::GpuMemoryBuffer* PpapiCommandBufferProxy::CreateGpuMemoryBuffer( 203 size_t width, 204 size_t height, 205 unsigned internalformat, 206 unsigned usage, 207 int32* id) { 208 NOTREACHED(); 209 return NULL; 210} 211 212void PpapiCommandBufferProxy::DestroyGpuMemoryBuffer(int32 id) { 213 NOTREACHED(); 214} 215 216bool PpapiCommandBufferProxy::Send(IPC::Message* msg) { 217 DCHECK(last_state_.error == gpu::error::kNoError); 218 219 if (channel_->Send(msg)) 220 return true; 221 222 last_state_.error = gpu::error::kLostContext; 223 return false; 224} 225 226void PpapiCommandBufferProxy::UpdateState( 227 const gpu::CommandBuffer::State& state, 228 bool success) { 229 // Handle wraparound. It works as long as we don't have more than 2B state 230 // updates in flight across which reordering occurs. 231 if (success) { 232 if (state.generation - last_state_.generation < 0x80000000U) { 233 last_state_ = state; 234 } 235 } else { 236 last_state_.error = gpu::error::kLostContext; 237 ++last_state_.generation; 238 } 239} 240 241void PpapiCommandBufferProxy::TryUpdateState() { 242 if (last_state_.error == gpu::error::kNoError) 243 shared_state()->Read(&last_state_); 244} 245 246gpu::CommandBufferSharedState* PpapiCommandBufferProxy::shared_state() const { 247 return reinterpret_cast<gpu::CommandBufferSharedState*>( 248 shared_state_shm_->memory()); 249} 250 251} // namespace proxy 252} // namespace ppapi 253