// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ppapi/proxy/ppapi_command_buffer_proxy.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/proxy/proxy_channel.h" #include "ppapi/shared_impl/api_id.h" #include "ppapi/shared_impl/host_resource.h" #include "ppapi/shared_impl/proxy_lock.h" namespace ppapi { namespace proxy { PpapiCommandBufferProxy::PpapiCommandBufferProxy( const ppapi::HostResource& resource, ProxyChannel* channel) : resource_(resource), channel_(channel) { } PpapiCommandBufferProxy::~PpapiCommandBufferProxy() { // gpu::Buffers are no longer referenced, allowing shared memory objects to be // deleted, closing the handle in this process. } bool PpapiCommandBufferProxy::Initialize() { return true; } gpu::CommandBuffer::State PpapiCommandBufferProxy::GetLastState() { ppapi::ProxyLock::AssertAcquiredDebugOnly(); return last_state_; } int32 PpapiCommandBufferProxy::GetLastToken() { ppapi::ProxyLock::AssertAcquiredDebugOnly(); return last_state_.token; } void PpapiCommandBufferProxy::Flush(int32 put_offset) { if (last_state_.error != gpu::error::kNoError) return; IPC::Message* message = new PpapiHostMsg_PPBGraphics3D_AsyncFlush( ppapi::API_ID_PPB_GRAPHICS_3D, resource_, put_offset); // Do not let a synchronous flush hold up this message. If this handler is // deferred until after the synchronous flush completes, it will overwrite the // cached last_state_ with out-of-date data. message->set_unblock(true); Send(message); } void PpapiCommandBufferProxy::WaitForTokenInRange(int32 start, int32 end) { if (last_state_.error != gpu::error::kNoError) return; bool success; gpu::CommandBuffer::State state; if (Send(new PpapiHostMsg_PPBGraphics3D_WaitForTokenInRange( ppapi::API_ID_PPB_GRAPHICS_3D, resource_, start, end, &state, &success))) UpdateState(state, success); } void PpapiCommandBufferProxy::WaitForGetOffsetInRange(int32 start, int32 end) { if (last_state_.error != gpu::error::kNoError) return; bool success; gpu::CommandBuffer::State state; if (Send(new PpapiHostMsg_PPBGraphics3D_WaitForGetOffsetInRange( ppapi::API_ID_PPB_GRAPHICS_3D, resource_, start, end, &state, &success))) UpdateState(state, success); } void PpapiCommandBufferProxy::SetGetBuffer(int32 transfer_buffer_id) { if (last_state_.error == gpu::error::kNoError) { Send(new PpapiHostMsg_PPBGraphics3D_SetGetBuffer( ppapi::API_ID_PPB_GRAPHICS_3D, resource_, transfer_buffer_id)); } } scoped_refptr<gpu::Buffer> PpapiCommandBufferProxy::CreateTransferBuffer( size_t size, int32* id) { *id = -1; if (last_state_.error != gpu::error::kNoError) return NULL; // Assuming we are in the renderer process, the service is responsible for // duplicating the handle. This might not be true for NaCl. ppapi::proxy::SerializedHandle handle( ppapi::proxy::SerializedHandle::SHARED_MEMORY); if (!Send(new PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer( ppapi::API_ID_PPB_GRAPHICS_3D, resource_, size, id, &handle))) { return NULL; } if (*id <= 0 || !handle.is_shmem()) return NULL; scoped_ptr<base::SharedMemory> shared_memory( new base::SharedMemory(handle.shmem(), false)); // Map the shared memory on demand. if (!shared_memory->memory()) { if (!shared_memory->Map(handle.size())) { *id = -1; return NULL; } } return gpu::MakeBufferFromSharedMemory(shared_memory.Pass(), handle.size()); } void PpapiCommandBufferProxy::DestroyTransferBuffer(int32 id) { if (last_state_.error != gpu::error::kNoError) return; Send(new PpapiHostMsg_PPBGraphics3D_DestroyTransferBuffer( ppapi::API_ID_PPB_GRAPHICS_3D, resource_, id)); } void PpapiCommandBufferProxy::Echo(const base::Closure& callback) { NOTREACHED(); } uint32 PpapiCommandBufferProxy::CreateStreamTexture(uint32 texture_id) { NOTREACHED(); return 0; } uint32 PpapiCommandBufferProxy::InsertSyncPoint() { uint32 sync_point = 0; if (last_state_.error == gpu::error::kNoError) { Send(new PpapiHostMsg_PPBGraphics3D_InsertSyncPoint( ppapi::API_ID_PPB_GRAPHICS_3D, resource_, &sync_point)); } return sync_point; } void PpapiCommandBufferProxy::SignalSyncPoint(uint32 sync_point, const base::Closure& callback) { NOTREACHED(); } void PpapiCommandBufferProxy::SignalQuery(uint32 query, const base::Closure& callback) { NOTREACHED(); } void PpapiCommandBufferProxy::SetSurfaceVisible(bool visible) { NOTREACHED(); } gpu::Capabilities PpapiCommandBufferProxy::GetCapabilities() { // TODO(boliu): Need to implement this to use cc in Pepper. Tracked in // crbug.com/325391. return gpu::Capabilities(); } gfx::GpuMemoryBuffer* PpapiCommandBufferProxy::CreateGpuMemoryBuffer( size_t width, size_t height, unsigned internalformat, unsigned usage, int32* id) { NOTREACHED(); return NULL; } void PpapiCommandBufferProxy::DestroyGpuMemoryBuffer(int32 id) { NOTREACHED(); } bool PpapiCommandBufferProxy::Send(IPC::Message* msg) { DCHECK(last_state_.error == gpu::error::kNoError); if (channel_->Send(msg)) return true; last_state_.error = gpu::error::kLostContext; return false; } void PpapiCommandBufferProxy::UpdateState( const gpu::CommandBuffer::State& state, bool success) { // Handle wraparound. It works as long as we don't have more than 2B state // updates in flight across which reordering occurs. if (success) { if (state.generation - last_state_.generation < 0x80000000U) { last_state_ = state; } } else { last_state_.error = gpu::error::kLostContext; ++last_state_.generation; } } } // namespace proxy } // namespace ppapi