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/transfer_buffer.h"
14#include "gpu/command_buffer/common/constants.h"
15#include "gpu/command_buffer/common/gles2_cmd_utils.h"
16#include "gpu/command_buffer/service/command_buffer_service.h"
17#include "gpu/command_buffer/service/context_group.h"
18#include "gpu/command_buffer/service/gl_context_virtual.h"
19#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
20#include "gpu/command_buffer/service/gpu_control_service.h"
21#include "gpu/command_buffer/service/gpu_scheduler.h"
22#include "gpu/command_buffer/service/image_manager.h"
23#include "gpu/command_buffer/service/mailbox_manager.h"
24#include "testing/gtest/include/gtest/gtest.h"
25#include "ui/gl/gl_context.h"
26#include "ui/gl/gl_share_group.h"
27#include "ui/gl/gl_surface.h"
28
29namespace gpu {
30
31int GLManager::use_count_;
32scoped_refptr<gfx::GLShareGroup>* GLManager::base_share_group_;
33scoped_refptr<gfx::GLSurface>* GLManager::base_surface_;
34scoped_refptr<gfx::GLContext>* GLManager::base_context_;
35
36GLManager::Options::Options()
37    : size(4, 4),
38      share_group_manager(NULL),
39      share_mailbox_manager(NULL),
40      virtual_manager(NULL),
41      bind_generates_resource(false),
42      context_lost_allowed(false),
43      image_manager(NULL) {
44}
45
46GLManager::GLManager()
47    : context_lost_allowed_(false) {
48  SetupBaseContext();
49}
50
51GLManager::~GLManager() {
52  --use_count_;
53  if (!use_count_) {
54    if (base_share_group_) {
55      delete base_context_;
56      base_context_ = NULL;
57    }
58    if (base_surface_) {
59      delete base_surface_;
60      base_surface_ = NULL;
61    }
62    if (base_context_) {
63      delete base_context_;
64      base_context_ = NULL;
65    }
66  }
67}
68
69void GLManager::Initialize(const GLManager::Options& options) {
70  const int32 kCommandBufferSize = 1024 * 1024;
71  const size_t kStartTransferBufferSize = 4 * 1024 * 1024;
72  const size_t kMinTransferBufferSize = 1 * 256 * 1024;
73  const size_t kMaxTransferBufferSize = 16 * 1024 * 1024;
74
75  context_lost_allowed_ = options.context_lost_allowed;
76
77  gles2::MailboxManager* mailbox_manager = NULL;
78  if (options.share_mailbox_manager) {
79    mailbox_manager = options.share_mailbox_manager->mailbox_manager();
80  } else if (options.share_group_manager) {
81    mailbox_manager = options.share_group_manager->mailbox_manager();
82  }
83
84  gfx::GLShareGroup* share_group = NULL;
85  if (options.share_group_manager) {
86    share_group = options.share_group_manager->share_group();
87  } else if (options.share_mailbox_manager) {
88    share_group = options.share_mailbox_manager->share_group();
89  }
90
91  gles2::ContextGroup* context_group = NULL;
92  gles2::ShareGroup* client_share_group = NULL;
93  if (options.share_group_manager) {
94    context_group = options.share_group_manager->decoder_->GetContextGroup();
95    client_share_group =
96      options.share_group_manager->gles2_implementation()->share_group();
97  }
98
99  gfx::GLContext* real_gl_context = NULL;
100  if (options.virtual_manager) {
101    real_gl_context = options.virtual_manager->context();
102  }
103
104  mailbox_manager_ =
105      mailbox_manager ? mailbox_manager : new gles2::MailboxManager;
106  share_group_ =
107      share_group ? share_group : new gfx::GLShareGroup;
108
109  gfx::GpuPreference gpu_preference(gfx::PreferDiscreteGpu);
110  std::vector<int32> attribs;
111  gles2::ContextCreationAttribHelper attrib_helper;
112  attrib_helper.red_size_ = 8;
113  attrib_helper.green_size_ = 8;
114  attrib_helper.blue_size_ = 8;
115  attrib_helper.alpha_size_ = 8;
116  attrib_helper.depth_size_ = 16;
117  attrib_helper.Serialize(&attribs);
118
119  if (!context_group) {
120    context_group = new gles2::ContextGroup(mailbox_manager_.get(),
121                                            options.image_manager,
122                                            NULL,
123                                            NULL,
124                                            NULL,
125                                            options.bind_generates_resource);
126  }
127
128  decoder_.reset(::gpu::gles2::GLES2Decoder::Create(context_group));
129
130  command_buffer_.reset(new CommandBufferService(
131      decoder_->GetContextGroup()->transfer_buffer_manager()));
132  ASSERT_TRUE(command_buffer_->Initialize())
133      << "could not create command buffer service";
134
135  gpu_scheduler_.reset(new GpuScheduler(command_buffer_.get(),
136                                        decoder_.get(),
137                                        decoder_.get()));
138
139  decoder_->set_engine(gpu_scheduler_.get());
140
141  surface_ = gfx::GLSurface::CreateOffscreenGLSurface(options.size);
142  ASSERT_TRUE(surface_.get() != NULL) << "could not create offscreen surface";
143
144  if (real_gl_context) {
145    context_ = scoped_refptr<gfx::GLContext>(new gpu::GLContextVirtual(
146        share_group_.get(), real_gl_context, decoder_->AsWeakPtr()));
147    ASSERT_TRUE(context_->Initialize(
148        surface_.get(), gfx::PreferIntegratedGpu));
149  } else {
150    if (base_context_) {
151      context_ = scoped_refptr<gfx::GLContext>(new gpu::GLContextVirtual(
152          share_group_.get(), base_context_->get(), decoder_->AsWeakPtr()));
153      ASSERT_TRUE(context_->Initialize(
154          surface_.get(), gfx::PreferIntegratedGpu));
155    } else {
156      context_ = gfx::GLContext::CreateGLContext(share_group_.get(),
157                                                 surface_.get(),
158                                                 gpu_preference);
159    }
160  }
161  ASSERT_TRUE(context_.get() != NULL) << "could not create GL context";
162
163  ASSERT_TRUE(context_->MakeCurrent(surface_.get()));
164
165  ASSERT_TRUE(decoder_->Initialize(
166      surface_.get(),
167      context_.get(),
168      true,
169      options.size,
170      ::gpu::gles2::DisallowedFeatures(),
171      attribs)) << "could not initialize decoder";
172
173  gpu_control_.reset(
174      new GpuControlService(decoder_->GetContextGroup()->image_manager(),
175                            options.gpu_memory_buffer_factory,
176                            decoder_->GetContextGroup()->mailbox_manager(),
177                            decoder_->GetQueryManager(),
178                            decoder_->GetCapabilities()));
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  bool free_everything_when_invisible = false;
193
194  // Create the object exposing the OpenGL API.
195  gles2_implementation_.reset(new gles2::GLES2Implementation(
196      gles2_helper_.get(),
197      client_share_group,
198      transfer_buffer_.get(),
199      options.bind_generates_resource,
200      free_everything_when_invisible ,
201      gpu_control_.get()));
202
203  ASSERT_TRUE(gles2_implementation_->Initialize(
204      kStartTransferBufferSize,
205      kMinTransferBufferSize,
206      kMaxTransferBufferSize,
207      gpu::gles2::GLES2Implementation::kNoLimit))
208          << "Could not init GLES2Implementation";
209
210  MakeCurrent();
211}
212
213void GLManager::SetupBaseContext() {
214  if (use_count_) {
215    #if defined(OS_ANDROID)
216      base_share_group_ = new scoped_refptr<gfx::GLShareGroup>(
217          new gfx::GLShareGroup);
218      gfx::Size size(4, 4);
219      base_surface_ = new scoped_refptr<gfx::GLSurface>(
220          gfx::GLSurface::CreateOffscreenGLSurface(size));
221      gfx::GpuPreference gpu_preference(gfx::PreferDiscreteGpu);
222      base_context_ = new scoped_refptr<gfx::GLContext>(
223          gfx::GLContext::CreateGLContext(base_share_group_->get(),
224                                          base_surface_->get(),
225                                          gpu_preference));
226    #endif
227  }
228  ++use_count_;
229}
230
231void GLManager::MakeCurrent() {
232  ::gles2::SetGLContext(gles2_implementation_.get());
233}
234
235void GLManager::SetSurface(gfx::GLSurface* surface) {
236  decoder_->SetSurface(surface);
237}
238
239void GLManager::Destroy() {
240  if (gles2_implementation_.get()) {
241    MakeCurrent();
242    EXPECT_TRUE(glGetError() == GL_NONE);
243    gles2_implementation_->Flush();
244    gles2_implementation_.reset();
245  }
246  transfer_buffer_.reset();
247  gles2_helper_.reset();
248  command_buffer_.reset();
249  if (decoder_.get()) {
250    decoder_->MakeCurrent();
251    decoder_->Destroy(true);
252    decoder_.reset();
253  }
254}
255
256const gpu::gles2::FeatureInfo::Workarounds& GLManager::workarounds() const {
257  return decoder_->GetContextGroup()->feature_info()->workarounds();
258}
259
260void GLManager::PumpCommands() {
261  decoder_->MakeCurrent();
262  gpu_scheduler_->PutChanged();
263  ::gpu::CommandBuffer::State state = command_buffer_->GetState();
264  if (!context_lost_allowed_) {
265    ASSERT_EQ(::gpu::error::kNoError, state.error);
266  }
267}
268
269bool GLManager::GetBufferChanged(int32 transfer_buffer_id) {
270  return gpu_scheduler_->SetGetBuffer(transfer_buffer_id);
271}
272
273}  // namespace gpu
274