command_buffer_impl.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
1// Copyright 2013 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/services/gles2/command_buffer_impl.h"
6
7#include "base/bind.h"
8#include "base/memory/shared_memory.h"
9
10#include "gpu/command_buffer/common/constants.h"
11#include "gpu/command_buffer/service/command_buffer_service.h"
12#include "gpu/command_buffer/service/context_group.h"
13#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
14#include "gpu/command_buffer/service/gpu_control_service.h"
15#include "gpu/command_buffer/service/gpu_scheduler.h"
16#include "gpu/command_buffer/service/image_manager.h"
17#include "gpu/command_buffer/service/mailbox_manager.h"
18#include "gpu/command_buffer/service/memory_tracking.h"
19#include "mojo/public/cpp/bindings/allocation_scope.h"
20#include "mojo/services/gles2/command_buffer_type_conversions.h"
21#include "mojo/services/gles2/mojo_buffer_backing.h"
22#include "ui/gl/gl_context.h"
23#include "ui/gl/gl_surface.h"
24
25namespace mojo {
26namespace services {
27
28namespace {
29
30class MemoryTrackerStub : public gpu::gles2::MemoryTracker {
31 public:
32  MemoryTrackerStub() {}
33
34  virtual void TrackMemoryAllocatedChange(size_t old_size,
35                                          size_t new_size,
36                                          gpu::gles2::MemoryTracker::Pool pool)
37      OVERRIDE {}
38
39  virtual bool EnsureGPUMemoryAvailable(size_t size_needed) OVERRIDE {
40    return true;
41  };
42
43 private:
44  virtual ~MemoryTrackerStub() {}
45
46  DISALLOW_COPY_AND_ASSIGN(MemoryTrackerStub);
47};
48
49}  // anonymous namespace
50
51CommandBufferImpl::CommandBufferImpl(ScopedCommandBufferClientHandle client,
52                                     gfx::AcceleratedWidget widget,
53                                     const gfx::Size& size)
54    : client_(client.Pass(), this), widget_(widget), size_(size) {}
55
56CommandBufferImpl::~CommandBufferImpl() { client_->DidDestroy(); }
57
58void CommandBufferImpl::Initialize(
59    ScopedCommandBufferSyncClientHandle sync_client,
60    mojo::ScopedSharedBufferHandle shared_state) {
61  sync_client_.reset(sync_client.Pass(), NULL);
62  sync_client_->DidInitialize(DoInitialize(shared_state.Pass()));
63}
64
65bool CommandBufferImpl::DoInitialize(
66    mojo::ScopedSharedBufferHandle shared_state) {
67  // TODO(piman): offscreen surface.
68  scoped_refptr<gfx::GLSurface> surface =
69      gfx::GLSurface::CreateViewGLSurface(widget_);
70  if (!surface.get())
71    return false;
72
73  // TODO(piman): context sharing, virtual contexts, gpu preference.
74  scoped_refptr<gfx::GLContext> context = gfx::GLContext::CreateGLContext(
75      NULL, surface.get(), gfx::PreferIntegratedGpu);
76  if (!context.get())
77    return false;
78
79  if (!context->MakeCurrent(surface.get()))
80    return false;
81
82  // TODO(piman): ShaderTranslatorCache is currently per-ContextGroup but
83  // only needs to be per-thread.
84  scoped_refptr<gpu::gles2::ContextGroup> context_group =
85      new gpu::gles2::ContextGroup(NULL,
86                                   NULL,
87                                   new MemoryTrackerStub,
88                                   new gpu::gles2::ShaderTranslatorCache,
89                                   NULL,
90                                   true);
91
92  command_buffer_.reset(
93      new gpu::CommandBufferService(context_group->transfer_buffer_manager()));
94  bool result = command_buffer_->Initialize();
95  DCHECK(result);
96
97  decoder_.reset(::gpu::gles2::GLES2Decoder::Create(context_group.get()));
98  scheduler_.reset(new gpu::GpuScheduler(
99      command_buffer_.get(), decoder_.get(), decoder_.get()));
100  decoder_->set_engine(scheduler_.get());
101
102  gpu::gles2::DisallowedFeatures disallowed_features;
103
104  // TODO(piman): attributes.
105  std::vector<int32> attrib_vector;
106  if (!decoder_->Initialize(surface,
107                            context,
108                            false /* offscreen */,
109                            size_,
110                            disallowed_features,
111                            attrib_vector))
112    return false;
113
114  gpu_control_.reset(
115      new gpu::GpuControlService(context_group->image_manager(),
116                                 NULL,
117                                 context_group->mailbox_manager(),
118                                 NULL,
119                                 decoder_->GetCapabilities()));
120
121  command_buffer_->SetPutOffsetChangeCallback(base::Bind(
122      &gpu::GpuScheduler::PutChanged, base::Unretained(scheduler_.get())));
123  command_buffer_->SetGetBufferChangeCallback(base::Bind(
124      &gpu::GpuScheduler::SetGetBuffer, base::Unretained(scheduler_.get())));
125  command_buffer_->SetParseErrorCallback(
126      base::Bind(&CommandBufferImpl::OnParseError, base::Unretained(this)));
127
128  // TODO(piman): other callbacks
129
130  const size_t kSize = sizeof(gpu::CommandBufferSharedState);
131  scoped_ptr<gpu::BufferBacking> backing(
132      gles2::MojoBufferBacking::Create(shared_state.Pass(), kSize));
133  if (!backing.get())
134    return false;
135
136  command_buffer_->SetSharedStateBuffer(backing.Pass());
137  return true;
138}
139
140void CommandBufferImpl::SetGetBuffer(int32_t buffer) {
141  command_buffer_->SetGetBuffer(buffer);
142}
143
144void CommandBufferImpl::Flush(int32_t put_offset) {
145  command_buffer_->Flush(put_offset);
146}
147
148void CommandBufferImpl::MakeProgress(int32_t last_get_offset) {
149  // TODO(piman): handle out-of-order.
150  AllocationScope scope;
151  sync_client_->DidMakeProgress(command_buffer_->GetLastState());
152}
153
154void CommandBufferImpl::RegisterTransferBuffer(
155    int32_t id,
156    mojo::ScopedSharedBufferHandle transfer_buffer,
157    uint32_t size) {
158  // Take ownership of the memory and map it into this process.
159  // This validates the size.
160  scoped_ptr<gpu::BufferBacking> backing(
161      gles2::MojoBufferBacking::Create(transfer_buffer.Pass(), size));
162  if (!backing.get()) {
163    DVLOG(0) << "Failed to map shared memory.";
164    return;
165  }
166  command_buffer_->RegisterTransferBuffer(id, backing.Pass());
167}
168
169void CommandBufferImpl::DestroyTransferBuffer(int32_t id) {
170  command_buffer_->DestroyTransferBuffer(id);
171}
172
173void CommandBufferImpl::Echo(const Callback<void()>& callback) {
174  callback.Run();
175}
176
177void CommandBufferImpl::RequestAnimationFrames() {
178  timer_.Start(FROM_HERE,
179               base::TimeDelta::FromMilliseconds(16),
180               this,
181               &CommandBufferImpl::DrawAnimationFrame);
182}
183
184void CommandBufferImpl::CancelAnimationFrames() { timer_.Stop(); }
185
186void CommandBufferImpl::OnParseError() {
187  gpu::CommandBuffer::State state = command_buffer_->GetLastState();
188  client_->LostContext(state.context_lost_reason);
189}
190
191void CommandBufferImpl::DrawAnimationFrame() { client_->DrawAnimationFrame(); }
192
193}  // namespace services
194}  // namespace mojo
195