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