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