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 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 44 CommandBufferDelegate::~CommandBufferDelegate() {} 45 46 void CommandBufferDelegate::ContextLost() {} 47 void CommandBufferDelegate::DrawAnimationFrame() {} 48 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 64 CommandBufferClientImpl::~CommandBufferClientImpl() {} 65 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 95 gpu::CommandBuffer::State CommandBufferClientImpl::GetLastState() { 96 return last_state_; 97 } 98 99 int32 CommandBufferClientImpl::GetLastToken() { 100 TryUpdateState(); 101 return last_state_.token; 102 } 103 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 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 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 130 void CommandBufferClientImpl::SetGetBuffer(int32 shm_id) { 131 command_buffer_->SetGetBuffer(shm_id); 132 last_put_offset_ = -1; 133 } 134 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 158 void CommandBufferClientImpl::DestroyTransferBuffer(int32 id) { 159 command_buffer_->DestroyTransferBuffer(id); 160 } 161 162 gpu::Capabilities CommandBufferClientImpl::GetCapabilities() { 163 // TODO(piman) 164 NOTIMPLEMENTED(); 165 return gpu::Capabilities(); 166 } 167 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 179 void CommandBufferClientImpl::DestroyGpuMemoryBuffer(int32 id) { 180 // TODO(piman) 181 NOTIMPLEMENTED(); 182 } 183 184 uint32 CommandBufferClientImpl::InsertSyncPoint() { 185 // TODO(piman) 186 NOTIMPLEMENTED(); 187 return 0; 188 } 189 190 void CommandBufferClientImpl::SignalSyncPoint(uint32 sync_point, 191 const base::Closure& callback) { 192 // TODO(piman) 193 NOTIMPLEMENTED(); 194 } 195 196 void CommandBufferClientImpl::SignalQuery(uint32 query, 197 const base::Closure& callback) { 198 // TODO(piman) 199 NOTIMPLEMENTED(); 200 } 201 202 void CommandBufferClientImpl::SetSurfaceVisible(bool visible) { 203 // TODO(piman) 204 NOTIMPLEMENTED(); 205 } 206 207 void CommandBufferClientImpl::Echo(const base::Closure& callback) { 208 command_buffer_->Echo(callback); 209 } 210 211 uint32 CommandBufferClientImpl::CreateStreamTexture(uint32 texture_id) { 212 // TODO(piman) 213 NOTIMPLEMENTED(); 214 return 0; 215 } 216 217 void CommandBufferClientImpl::RequestAnimationFrames() { 218 command_buffer_->RequestAnimationFrames(); 219 } 220 221 void CommandBufferClientImpl::CancelAnimationFrames() { 222 command_buffer_->CancelAnimationFrames(); 223 } 224 225 void CommandBufferClientImpl::DidInitialize(bool success) { 226 initialize_result_ = success; 227 } 228 229 void CommandBufferClientImpl::DidMakeProgress(CommandBufferStatePtr state) { 230 if (state->generation - last_state_.generation < 0x80000000U) 231 last_state_ = state.To<State>(); 232 } 233 234 void CommandBufferClientImpl::DidDestroy() { 235 LostContext(gpu::error::kUnknown); 236 } 237 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 245 void CommandBufferClientImpl::OnConnectionError() { 246 LostContext(gpu::error::kUnknown); 247 } 248 249 void CommandBufferClientImpl::TryUpdateState() { 250 if (last_state_.error == gpu::error::kNoError) 251 shared_state()->Read(&last_state_); 252 } 253 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 264 void CommandBufferClientImpl::DrawAnimationFrame() { 265 delegate_->DrawAnimationFrame(); 266 } 267 268 } // namespace gles2 269 } // namespace mojo 270