Home | History | Annotate | Download | only in gles2
      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