1 // Copyright 2014 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 "mojo/gles2/command_buffer_client_impl.h"
6
7 #include <limits>
8
9 #include "base/logging.h"
10 #include "base/process/process_handle.h"
11 #include "mojo/public/cpp/bindings/sync_dispatcher.h"
12 #include "mojo/services/gles2/command_buffer_type_conversions.h"
13 #include "mojo/services/gles2/mojo_buffer_backing.h"
14
15 namespace mojo {
16 namespace gles2 {
17
18 namespace {
19
CreateMapAndDupSharedBuffer(size_t size,void ** memory,mojo::ScopedSharedBufferHandle * handle,mojo::ScopedSharedBufferHandle * duped)20 bool CreateMapAndDupSharedBuffer(size_t size,
21 void** memory,
22 mojo::ScopedSharedBufferHandle* handle,
23 mojo::ScopedSharedBufferHandle* duped) {
24 MojoResult result = mojo::CreateSharedBuffer(NULL, size, handle);
25 if (result != MOJO_RESULT_OK)
26 return false;
27 DCHECK(handle->is_valid());
28
29 result = mojo::DuplicateBuffer(handle->get(), NULL, duped);
30 if (result != MOJO_RESULT_OK)
31 return false;
32 DCHECK(duped->is_valid());
33
34 result = mojo::MapBuffer(
35 handle->get(), 0, size, memory, MOJO_MAP_BUFFER_FLAG_NONE);
36 if (result != MOJO_RESULT_OK)
37 return false;
38 DCHECK(*memory);
39
40 return true;
41 }
42 }
43
~CommandBufferDelegate()44 CommandBufferDelegate::~CommandBufferDelegate() {}
45
ContextLost()46 void CommandBufferDelegate::ContextLost() {}
DrawAnimationFrame()47 void CommandBufferDelegate::DrawAnimationFrame() {}
48
CommandBufferClientImpl(CommandBufferDelegate * delegate,const MojoAsyncWaiter * async_waiter,ScopedMessagePipeHandle command_buffer_handle)49 CommandBufferClientImpl::CommandBufferClientImpl(
50 CommandBufferDelegate* delegate,
51 const MojoAsyncWaiter* async_waiter,
52 ScopedMessagePipeHandle command_buffer_handle)
53 : delegate_(delegate),
54 shared_state_(NULL),
55 last_put_offset_(-1),
56 next_transfer_buffer_id_(0),
57 initialize_result_(false),
58 async_waiter_(async_waiter) {
59 command_buffer_.Bind(command_buffer_handle.Pass(), async_waiter);
60 command_buffer_.set_error_handler(this);
61 command_buffer_.set_client(this);
62 }
63
~CommandBufferClientImpl()64 CommandBufferClientImpl::~CommandBufferClientImpl() {}
65
Initialize()66 bool CommandBufferClientImpl::Initialize() {
67 const size_t kSharedStateSize = sizeof(gpu::CommandBufferSharedState);
68 void* memory = NULL;
69 mojo::ScopedSharedBufferHandle duped;
70 bool result = CreateMapAndDupSharedBuffer(
71 kSharedStateSize, &memory, &shared_state_handle_, &duped);
72 if (!result)
73 return false;
74
75 shared_state_ = static_cast<gpu::CommandBufferSharedState*>(memory);
76
77 shared_state()->Initialize();
78
79 // TODO(darin): We need better sugar for sync calls.
80 MessagePipe sync_pipe;
81 sync_dispatcher_.reset(new SyncDispatcher<CommandBufferSyncClient>(
82 sync_pipe.handle0.Pass(), this));
83 CommandBufferSyncClientPtr sync_client =
84 MakeProxy<CommandBufferSyncClient>(sync_pipe.handle1.Pass(),
85 async_waiter_);
86 command_buffer_->Initialize(sync_client.Pass(), duped.Pass());
87 // Wait for DidInitialize to come on the sync client pipe.
88 if (!sync_dispatcher_->WaitAndDispatchOneMessage()) {
89 VLOG(1) << "Channel encountered error while creating command buffer";
90 return false;
91 }
92 return initialize_result_;
93 }
94
GetLastState()95 gpu::CommandBuffer::State CommandBufferClientImpl::GetLastState() {
96 return last_state_;
97 }
98
GetLastToken()99 int32 CommandBufferClientImpl::GetLastToken() {
100 TryUpdateState();
101 return last_state_.token;
102 }
103
Flush(int32 put_offset)104 void CommandBufferClientImpl::Flush(int32 put_offset) {
105 if (last_put_offset_ == put_offset)
106 return;
107
108 last_put_offset_ = put_offset;
109 command_buffer_->Flush(put_offset);
110 }
111
WaitForTokenInRange(int32 start,int32 end)112 void CommandBufferClientImpl::WaitForTokenInRange(int32 start, int32 end) {
113 TryUpdateState();
114 while (!InRange(start, end, last_state_.token) &&
115 last_state_.error == gpu::error::kNoError) {
116 MakeProgressAndUpdateState();
117 TryUpdateState();
118 }
119 }
120
WaitForGetOffsetInRange(int32 start,int32 end)121 void CommandBufferClientImpl::WaitForGetOffsetInRange(int32 start, int32 end) {
122 TryUpdateState();
123 while (!InRange(start, end, last_state_.get_offset) &&
124 last_state_.error == gpu::error::kNoError) {
125 MakeProgressAndUpdateState();
126 TryUpdateState();
127 }
128 }
129
SetGetBuffer(int32 shm_id)130 void CommandBufferClientImpl::SetGetBuffer(int32 shm_id) {
131 command_buffer_->SetGetBuffer(shm_id);
132 last_put_offset_ = -1;
133 }
134
CreateTransferBuffer(size_t size,int32 * id)135 scoped_refptr<gpu::Buffer> CommandBufferClientImpl::CreateTransferBuffer(
136 size_t size,
137 int32* id) {
138 if (size >= std::numeric_limits<uint32_t>::max())
139 return NULL;
140
141 void* memory = NULL;
142 mojo::ScopedSharedBufferHandle handle;
143 mojo::ScopedSharedBufferHandle duped;
144 if (!CreateMapAndDupSharedBuffer(size, &memory, &handle, &duped))
145 return NULL;
146
147 *id = ++next_transfer_buffer_id_;
148
149 command_buffer_->RegisterTransferBuffer(
150 *id, duped.Pass(), static_cast<uint32_t>(size));
151
152 scoped_ptr<gpu::BufferBacking> backing(
153 new MojoBufferBacking(handle.Pass(), memory, size));
154 scoped_refptr<gpu::Buffer> buffer(new gpu::Buffer(backing.Pass()));
155 return buffer;
156 }
157
DestroyTransferBuffer(int32 id)158 void CommandBufferClientImpl::DestroyTransferBuffer(int32 id) {
159 command_buffer_->DestroyTransferBuffer(id);
160 }
161
GetCapabilities()162 gpu::Capabilities CommandBufferClientImpl::GetCapabilities() {
163 // TODO(piman)
164 NOTIMPLEMENTED();
165 return gpu::Capabilities();
166 }
167
CreateGpuMemoryBuffer(size_t width,size_t height,unsigned internalformat,unsigned usage,int32 * id)168 gfx::GpuMemoryBuffer* CommandBufferClientImpl::CreateGpuMemoryBuffer(
169 size_t width,
170 size_t height,
171 unsigned internalformat,
172 unsigned usage,
173 int32* id) {
174 // TODO(piman)
175 NOTIMPLEMENTED();
176 return NULL;
177 }
178
DestroyGpuMemoryBuffer(int32 id)179 void CommandBufferClientImpl::DestroyGpuMemoryBuffer(int32 id) {
180 // TODO(piman)
181 NOTIMPLEMENTED();
182 }
183
InsertSyncPoint()184 uint32 CommandBufferClientImpl::InsertSyncPoint() {
185 // TODO(piman)
186 NOTIMPLEMENTED();
187 return 0;
188 }
189
SignalSyncPoint(uint32 sync_point,const base::Closure & callback)190 void CommandBufferClientImpl::SignalSyncPoint(uint32 sync_point,
191 const base::Closure& callback) {
192 // TODO(piman)
193 NOTIMPLEMENTED();
194 }
195
SignalQuery(uint32 query,const base::Closure & callback)196 void CommandBufferClientImpl::SignalQuery(uint32 query,
197 const base::Closure& callback) {
198 // TODO(piman)
199 NOTIMPLEMENTED();
200 }
201
SetSurfaceVisible(bool visible)202 void CommandBufferClientImpl::SetSurfaceVisible(bool visible) {
203 // TODO(piman)
204 NOTIMPLEMENTED();
205 }
206
Echo(const base::Closure & callback)207 void CommandBufferClientImpl::Echo(const base::Closure& callback) {
208 command_buffer_->Echo(callback);
209 }
210
CreateStreamTexture(uint32 texture_id)211 uint32 CommandBufferClientImpl::CreateStreamTexture(uint32 texture_id) {
212 // TODO(piman)
213 NOTIMPLEMENTED();
214 return 0;
215 }
216
RequestAnimationFrames()217 void CommandBufferClientImpl::RequestAnimationFrames() {
218 command_buffer_->RequestAnimationFrames();
219 }
220
CancelAnimationFrames()221 void CommandBufferClientImpl::CancelAnimationFrames() {
222 command_buffer_->CancelAnimationFrames();
223 }
224
DidInitialize(bool success)225 void CommandBufferClientImpl::DidInitialize(bool success) {
226 initialize_result_ = success;
227 }
228
DidMakeProgress(CommandBufferStatePtr state)229 void CommandBufferClientImpl::DidMakeProgress(CommandBufferStatePtr state) {
230 if (state->generation - last_state_.generation < 0x80000000U)
231 last_state_ = state.To<State>();
232 }
233
DidDestroy()234 void CommandBufferClientImpl::DidDestroy() {
235 LostContext(gpu::error::kUnknown);
236 }
237
LostContext(int32_t lost_reason)238 void CommandBufferClientImpl::LostContext(int32_t lost_reason) {
239 last_state_.error = gpu::error::kLostContext;
240 last_state_.context_lost_reason =
241 static_cast<gpu::error::ContextLostReason>(lost_reason);
242 delegate_->ContextLost();
243 }
244
OnConnectionError()245 void CommandBufferClientImpl::OnConnectionError() {
246 LostContext(gpu::error::kUnknown);
247 }
248
TryUpdateState()249 void CommandBufferClientImpl::TryUpdateState() {
250 if (last_state_.error == gpu::error::kNoError)
251 shared_state()->Read(&last_state_);
252 }
253
MakeProgressAndUpdateState()254 void CommandBufferClientImpl::MakeProgressAndUpdateState() {
255 command_buffer_->MakeProgress(last_state_.get_offset);
256 if (!sync_dispatcher_->WaitAndDispatchOneMessage()) {
257 VLOG(1) << "Channel encountered error while waiting for command buffer";
258 // TODO(piman): is it ok for this to re-enter?
259 DidDestroy();
260 return;
261 }
262 }
263
DrawAnimationFrame()264 void CommandBufferClientImpl::DrawAnimationFrame() {
265 delegate_->DrawAnimationFrame();
266 }
267
268 } // namespace gles2
269 } // namespace mojo
270