1// Copyright (c) 2012 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 "gpu/command_buffer/tests/gl_manager.h"
6
7#include <vector>
8
9#include "base/at_exit.h"
10#include "base/bind.h"
11#include "gpu/command_buffer/client/gles2_implementation.h"
12#include "gpu/command_buffer/client/gles2_lib.h"
13#include "gpu/command_buffer/client/gpu_memory_buffer_factory.h"
14#include "gpu/command_buffer/client/transfer_buffer.h"
15#include "gpu/command_buffer/common/constants.h"
16#include "gpu/command_buffer/common/gles2_cmd_utils.h"
17#include "gpu/command_buffer/service/command_buffer_service.h"
18#include "gpu/command_buffer/service/context_group.h"
19#include "gpu/command_buffer/service/gl_context_virtual.h"
20#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
21#include "gpu/command_buffer/service/gpu_control_service.h"
22#include "gpu/command_buffer/service/gpu_scheduler.h"
23#include "gpu/command_buffer/service/image_manager.h"
24#include "gpu/command_buffer/service/mailbox_manager.h"
25#include "testing/gtest/include/gtest/gtest.h"
26#include "ui/gl/gl_context.h"
27#include "ui/gl/gl_share_group.h"
28#include "ui/gl/gl_surface.h"
29
30namespace gpu {
31
32int GLManager::use_count_;
33scoped_refptr<gfx::GLShareGroup>* GLManager::base_share_group_;
34scoped_refptr<gfx::GLSurface>* GLManager::base_surface_;
35scoped_refptr<gfx::GLContext>* GLManager::base_context_;
36
37GLManager::Options::Options()
38    : size(4, 4),
39      share_group_manager(NULL),
40      share_mailbox_manager(NULL),
41      virtual_manager(NULL),
42      bind_generates_resource(false),
43      lose_context_when_out_of_memory(false),
44      context_lost_allowed(false),
45      image_manager(NULL) {}
46
47GLManager::GLManager()
48    : context_lost_allowed_(false), gpu_memory_buffer_factory_(NULL) {
49  SetupBaseContext();
50}
51
52GLManager::~GLManager() {
53  --use_count_;
54  if (!use_count_) {
55    if (base_share_group_) {
56      delete base_context_;
57      base_context_ = NULL;
58    }
59    if (base_surface_) {
60      delete base_surface_;
61      base_surface_ = NULL;
62    }
63    if (base_context_) {
64      delete base_context_;
65      base_context_ = NULL;
66    }
67  }
68}
69
70void GLManager::Initialize(const GLManager::Options& options) {
71  const int32 kCommandBufferSize = 1024 * 1024;
72  const size_t kStartTransferBufferSize = 4 * 1024 * 1024;
73  const size_t kMinTransferBufferSize = 1 * 256 * 1024;
74  const size_t kMaxTransferBufferSize = 16 * 1024 * 1024;
75
76  context_lost_allowed_ = options.context_lost_allowed;
77
78  gles2::MailboxManager* mailbox_manager = NULL;
79  if (options.share_mailbox_manager) {
80    mailbox_manager = options.share_mailbox_manager->mailbox_manager();
81  } else if (options.share_group_manager) {
82    mailbox_manager = options.share_group_manager->mailbox_manager();
83  }
84
85  gfx::GLShareGroup* share_group = NULL;
86  if (options.share_group_manager) {
87    share_group = options.share_group_manager->share_group();
88  } else if (options.share_mailbox_manager) {
89    share_group = options.share_mailbox_manager->share_group();
90  }
91
92  gles2::ContextGroup* context_group = NULL;
93  gles2::ShareGroup* client_share_group = NULL;
94  if (options.share_group_manager) {
95    context_group = options.share_group_manager->decoder_->GetContextGroup();
96    client_share_group =
97      options.share_group_manager->gles2_implementation()->share_group();
98  }
99
100  gfx::GLContext* real_gl_context = NULL;
101  if (options.virtual_manager) {
102    real_gl_context = options.virtual_manager->context();
103  }
104
105  mailbox_manager_ =
106      mailbox_manager ? mailbox_manager : new gles2::MailboxManager;
107  share_group_ =
108      share_group ? share_group : new gfx::GLShareGroup;
109
110  gfx::GpuPreference gpu_preference(gfx::PreferDiscreteGpu);
111  std::vector<int32> attribs;
112  gles2::ContextCreationAttribHelper attrib_helper;
113  attrib_helper.red_size_ = 8;
114  attrib_helper.green_size_ = 8;
115  attrib_helper.blue_size_ = 8;
116  attrib_helper.alpha_size_ = 8;
117  attrib_helper.depth_size_ = 16;
118  attrib_helper.Serialize(&attribs);
119
120  if (!context_group) {
121    context_group =
122        new gles2::ContextGroup(mailbox_manager_.get(),
123                                options.image_manager,
124                                NULL,
125                                new gpu::gles2::ShaderTranslatorCache,
126                                NULL,
127                                options.bind_generates_resource);
128  }
129
130  decoder_.reset(::gpu::gles2::GLES2Decoder::Create(context_group));
131
132  command_buffer_.reset(new CommandBufferService(
133      decoder_->GetContextGroup()->transfer_buffer_manager()));
134  ASSERT_TRUE(command_buffer_->Initialize())
135      << "could not create command buffer service";
136
137  gpu_scheduler_.reset(new GpuScheduler(command_buffer_.get(),
138                                        decoder_.get(),
139                                        decoder_.get()));
140
141  decoder_->set_engine(gpu_scheduler_.get());
142
143  surface_ = gfx::GLSurface::CreateOffscreenGLSurface(options.size);
144  ASSERT_TRUE(surface_.get() != NULL) << "could not create offscreen surface";
145
146  if (base_context_) {
147    context_ = scoped_refptr<gfx::GLContext>(new gpu::GLContextVirtual(
148        share_group_.get(), base_context_->get(), decoder_->AsWeakPtr()));
149    ASSERT_TRUE(context_->Initialize(
150        surface_.get(), gfx::PreferIntegratedGpu));
151  } else {
152    if (real_gl_context) {
153      context_ = scoped_refptr<gfx::GLContext>(new gpu::GLContextVirtual(
154          share_group_.get(), real_gl_context, decoder_->AsWeakPtr()));
155      ASSERT_TRUE(context_->Initialize(
156          surface_.get(), gfx::PreferIntegratedGpu));
157    } else {
158      context_ = gfx::GLContext::CreateGLContext(share_group_.get(),
159                                                 surface_.get(),
160                                                 gpu_preference);
161    }
162  }
163  ASSERT_TRUE(context_.get() != NULL) << "could not create GL context";
164
165  ASSERT_TRUE(context_->MakeCurrent(surface_.get()));
166
167  ASSERT_TRUE(decoder_->Initialize(
168      surface_.get(),
169      context_.get(),
170      true,
171      options.size,
172      ::gpu::gles2::DisallowedFeatures(),
173      attribs)) << "could not initialize decoder";
174
175  gpu_control_service_.reset(
176      new GpuControlService(decoder_->GetContextGroup()->image_manager(),
177                            decoder_->GetQueryManager()));
178  gpu_memory_buffer_factory_ = options.gpu_memory_buffer_factory;
179
180  command_buffer_->SetPutOffsetChangeCallback(
181      base::Bind(&GLManager::PumpCommands, base::Unretained(this)));
182  command_buffer_->SetGetBufferChangeCallback(
183      base::Bind(&GLManager::GetBufferChanged, base::Unretained(this)));
184
185  // Create the GLES2 helper, which writes the command buffer protocol.
186  gles2_helper_.reset(new gles2::GLES2CmdHelper(command_buffer_.get()));
187  ASSERT_TRUE(gles2_helper_->Initialize(kCommandBufferSize));
188
189  // Create a transfer buffer.
190  transfer_buffer_.reset(new TransferBuffer(gles2_helper_.get()));
191
192  // Create the object exposing the OpenGL API.
193  gles2_implementation_.reset(
194      new gles2::GLES2Implementation(gles2_helper_.get(),
195                                     client_share_group,
196                                     transfer_buffer_.get(),
197                                     options.bind_generates_resource,
198                                     options.lose_context_when_out_of_memory,
199                                     this));
200
201  ASSERT_TRUE(gles2_implementation_->Initialize(
202      kStartTransferBufferSize,
203      kMinTransferBufferSize,
204      kMaxTransferBufferSize,
205      gpu::gles2::GLES2Implementation::kNoLimit))
206          << "Could not init GLES2Implementation";
207
208  MakeCurrent();
209}
210
211void GLManager::SetupBaseContext() {
212  if (use_count_) {
213    #if defined(OS_ANDROID)
214      base_share_group_ = new scoped_refptr<gfx::GLShareGroup>(
215          new gfx::GLShareGroup);
216      gfx::Size size(4, 4);
217      base_surface_ = new scoped_refptr<gfx::GLSurface>(
218          gfx::GLSurface::CreateOffscreenGLSurface(size));
219      gfx::GpuPreference gpu_preference(gfx::PreferDiscreteGpu);
220      base_context_ = new scoped_refptr<gfx::GLContext>(
221          gfx::GLContext::CreateGLContext(base_share_group_->get(),
222                                          base_surface_->get(),
223                                          gpu_preference));
224    #endif
225  }
226  ++use_count_;
227}
228
229void GLManager::MakeCurrent() {
230  ::gles2::SetGLContext(gles2_implementation_.get());
231}
232
233void GLManager::SetSurface(gfx::GLSurface* surface) {
234  decoder_->SetSurface(surface);
235}
236
237void GLManager::Destroy() {
238  if (gles2_implementation_.get()) {
239    MakeCurrent();
240    EXPECT_TRUE(glGetError() == GL_NONE);
241    gles2_implementation_->Flush();
242    gles2_implementation_.reset();
243  }
244  transfer_buffer_.reset();
245  gles2_helper_.reset();
246  command_buffer_.reset();
247  if (decoder_.get()) {
248    decoder_->MakeCurrent();
249    decoder_->Destroy(true);
250    decoder_.reset();
251  }
252}
253
254const gpu::gles2::FeatureInfo::Workarounds& GLManager::workarounds() const {
255  return decoder_->GetContextGroup()->feature_info()->workarounds();
256}
257
258void GLManager::PumpCommands() {
259  decoder_->MakeCurrent();
260  gpu_scheduler_->PutChanged();
261  ::gpu::CommandBuffer::State state = command_buffer_->GetLastState();
262  if (!context_lost_allowed_) {
263    ASSERT_EQ(::gpu::error::kNoError, state.error);
264  }
265}
266
267bool GLManager::GetBufferChanged(int32 transfer_buffer_id) {
268  return gpu_scheduler_->SetGetBuffer(transfer_buffer_id);
269}
270
271Capabilities GLManager::GetCapabilities() {
272  return decoder_->GetCapabilities();
273}
274
275gfx::GpuMemoryBuffer* GLManager::CreateGpuMemoryBuffer(
276    size_t width,
277    size_t height,
278    unsigned internalformat,
279    unsigned usage,
280    int32* id) {
281  *id = -1;
282  scoped_ptr<gfx::GpuMemoryBuffer> buffer(
283      gpu_memory_buffer_factory_->CreateGpuMemoryBuffer(
284          width, height, internalformat, usage));
285  if (!buffer.get())
286    return NULL;
287
288  static int32 next_id = 1;
289  *id = next_id++;
290  gpu_control_service_->RegisterGpuMemoryBuffer(
291      *id, buffer->GetHandle(), width, height, internalformat);
292  gfx::GpuMemoryBuffer* raw_buffer = buffer.get();
293  memory_buffers_.add(*id, buffer.Pass());
294  return raw_buffer;
295}
296
297void GLManager::DestroyGpuMemoryBuffer(int32 id) {
298  memory_buffers_.erase(id);
299  gpu_control_service_->UnregisterGpuMemoryBuffer(id);
300}
301
302uint32 GLManager::InsertSyncPoint() {
303  NOTIMPLEMENTED();
304  return 0u;
305}
306
307void GLManager::SignalSyncPoint(uint32 sync_point,
308                             const base::Closure& callback) {
309  NOTIMPLEMENTED();
310}
311
312void GLManager::SignalQuery(uint32 query, const base::Closure& callback) {
313  NOTIMPLEMENTED();
314}
315
316void GLManager::SetSurfaceVisible(bool visible) {
317  NOTIMPLEMENTED();
318}
319
320void GLManager::Echo(const base::Closure& callback) {
321  NOTIMPLEMENTED();
322}
323
324uint32 GLManager::CreateStreamTexture(uint32 texture_id) {
325  NOTIMPLEMENTED();
326  return 0;
327}
328
329}  // namespace gpu
330