display.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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/gles2_conform_support/egl/display.h"
6
7#include <vector>
8#include "base/bind.h"
9#include "base/bind_helpers.h"
10#include "gpu/command_buffer/client/gles2_implementation.h"
11#include "gpu/command_buffer/client/gles2_lib.h"
12#include "gpu/command_buffer/client/transfer_buffer.h"
13#include "gpu/command_buffer/service/context_group.h"
14#include "gpu/command_buffer/service/gpu_control_service.h"
15#include "gpu/command_buffer/service/transfer_buffer_manager.h"
16#include "gpu/gles2_conform_support/egl/config.h"
17#include "gpu/gles2_conform_support/egl/surface.h"
18
19namespace {
20const int32 kCommandBufferSize = 1024 * 1024;
21const int32 kTransferBufferSize = 512 * 1024;
22}
23
24namespace egl {
25
26Display::Display(EGLNativeDisplayType display_id)
27    : display_id_(display_id),
28      is_initialized_(false),
29      create_offscreen_(false),
30      create_offscreen_width_(0),
31      create_offscreen_height_(0) {
32}
33
34Display::~Display() {
35  gles2::Terminate();
36}
37
38bool Display::Initialize() {
39  gles2::Initialize();
40  is_initialized_ = true;
41  return true;
42}
43
44bool Display::IsValidConfig(EGLConfig config) {
45  return (config != NULL) && (config == config_.get());
46}
47
48bool Display::ChooseConfigs(EGLConfig* configs,
49                            EGLint config_size,
50                            EGLint* num_config) {
51  // TODO(alokp): Find out a way to find all configs. CommandBuffer currently
52  // does not support finding or choosing configs.
53  *num_config = 1;
54  if (configs != NULL) {
55    if (config_ == NULL) {
56      config_.reset(new Config);
57    }
58    configs[0] = config_.get();
59  }
60  return true;
61}
62
63bool Display::GetConfigs(EGLConfig* configs,
64                         EGLint config_size,
65                         EGLint* num_config) {
66  // TODO(alokp): Find out a way to find all configs. CommandBuffer currently
67  // does not support finding or choosing configs.
68  *num_config = 1;
69  if (configs != NULL) {
70    if (config_ == NULL) {
71      config_.reset(new Config);
72    }
73    configs[0] = config_.get();
74  }
75  return true;
76}
77
78bool Display::GetConfigAttrib(EGLConfig config,
79                              EGLint attribute,
80                              EGLint* value) {
81  const egl::Config* cfg = static_cast<egl::Config*>(config);
82  return cfg->GetAttrib(attribute, value);
83}
84
85bool Display::IsValidNativeWindow(EGLNativeWindowType win) {
86#if defined OS_WIN
87  return ::IsWindow(win) != FALSE;
88#else
89  // TODO(alokp): Validate window handle.
90  return true;
91#endif  // OS_WIN
92}
93
94bool Display::IsValidSurface(EGLSurface surface) {
95  return (surface != NULL) && (surface == surface_.get());
96}
97
98EGLSurface Display::CreateWindowSurface(EGLConfig config,
99                                        EGLNativeWindowType win,
100                                        const EGLint* attrib_list) {
101  if (surface_ != NULL) {
102    // We do not support more than one window surface.
103    return EGL_NO_SURFACE;
104  }
105
106  {
107    gpu::TransferBufferManager* manager = new gpu::TransferBufferManager();
108    transfer_buffer_manager_.reset(manager);
109    manager->Initialize();
110  }
111  scoped_ptr<gpu::CommandBufferService> command_buffer(
112      new gpu::CommandBufferService(transfer_buffer_manager_.get()));
113  if (!command_buffer->Initialize())
114    return NULL;
115
116  scoped_refptr<gpu::gles2::ContextGroup> group(
117      new gpu::gles2::ContextGroup(NULL, NULL, NULL, NULL, true));
118
119  decoder_.reset(gpu::gles2::GLES2Decoder::Create(group.get()));
120  if (!decoder_.get())
121    return EGL_NO_SURFACE;
122
123  gpu_scheduler_.reset(new gpu::GpuScheduler(command_buffer.get(),
124                                             decoder_.get(),
125                                             NULL));
126
127  decoder_->set_engine(gpu_scheduler_.get());
128  gfx::Size size(create_offscreen_width_, create_offscreen_height_);
129  if (create_offscreen_) {
130    gl_surface_ = gfx::GLSurface::CreateOffscreenGLSurface(size);
131    create_offscreen_ = false;
132    create_offscreen_width_ = 0;
133    create_offscreen_height_ = 0;
134  } else {
135    gl_surface_ = gfx::GLSurface::CreateViewGLSurface(win);
136  }
137  if (!gl_surface_.get())
138    return EGL_NO_SURFACE;
139
140  gl_context_ = gfx::GLContext::CreateGLContext(NULL,
141                                                gl_surface_.get(),
142                                                gfx::PreferDiscreteGpu);
143  if (!gl_context_.get())
144    return EGL_NO_SURFACE;
145
146  gl_context_->MakeCurrent(gl_surface_.get());
147
148  EGLint depth_size = 0;
149  EGLint alpha_size = 0;
150  EGLint stencil_size = 0;
151  GetConfigAttrib(config, EGL_DEPTH_SIZE, &depth_size);
152  GetConfigAttrib(config, EGL_ALPHA_SIZE, &alpha_size);
153  GetConfigAttrib(config, EGL_STENCIL_SIZE, &stencil_size);
154  std::vector<int32> attribs;
155  attribs.push_back(EGL_DEPTH_SIZE);
156  attribs.push_back(depth_size);
157  attribs.push_back(EGL_ALPHA_SIZE);
158  attribs.push_back(alpha_size);
159  attribs.push_back(EGL_STENCIL_SIZE);
160  attribs.push_back(stencil_size);
161  // TODO(gman): Insert attrib_list. Although ES 1.1 says it must be null
162  attribs.push_back(EGL_NONE);
163
164  if (!decoder_->Initialize(gl_surface_.get(),
165                            gl_context_.get(),
166                            gl_surface_->IsOffscreen(),
167                            size,
168                            gpu::gles2::DisallowedFeatures(),
169                            attribs)) {
170    return EGL_NO_SURFACE;
171  }
172
173  gpu_control_.reset(new gpu::GpuControlService(
174      NULL, NULL, group->mailbox_manager(), NULL, decoder_->GetCapabilities()));
175
176  command_buffer->SetPutOffsetChangeCallback(
177      base::Bind(&gpu::GpuScheduler::PutChanged,
178                 base::Unretained(gpu_scheduler_.get())));
179  command_buffer->SetGetBufferChangeCallback(
180      base::Bind(&gpu::GpuScheduler::SetGetBuffer,
181                 base::Unretained(gpu_scheduler_.get())));
182
183  scoped_ptr<gpu::gles2::GLES2CmdHelper> cmd_helper(
184      new gpu::gles2::GLES2CmdHelper(command_buffer.get()));
185  if (!cmd_helper->Initialize(kCommandBufferSize))
186    return NULL;
187
188  scoped_ptr<gpu::TransferBuffer> transfer_buffer(new gpu::TransferBuffer(
189      cmd_helper.get()));
190
191  command_buffer_.reset(command_buffer.release());
192  transfer_buffer_.reset(transfer_buffer.release());
193  gles2_cmd_helper_.reset(cmd_helper.release());
194  surface_.reset(new Surface(win));
195
196  return surface_.get();
197}
198
199void Display::DestroySurface(EGLSurface surface) {
200  DCHECK(IsValidSurface(surface));
201  gpu_scheduler_.reset();
202  if (decoder_.get()) {
203    decoder_->Destroy(true);
204  }
205  decoder_.reset();
206  gl_surface_ = NULL;
207  gl_context_ = NULL;
208  surface_.reset();
209}
210
211void Display::SwapBuffers(EGLSurface surface) {
212  DCHECK(IsValidSurface(surface));
213  context_->SwapBuffers();
214}
215
216bool Display::IsValidContext(EGLContext ctx) {
217  return (ctx != NULL) && (ctx == context_.get());
218}
219
220EGLContext Display::CreateContext(EGLConfig config,
221                                  EGLContext share_ctx,
222                                  const EGLint* attrib_list) {
223  DCHECK(IsValidConfig(config));
224  // TODO(alokp): Add support for shared contexts.
225  if (share_ctx != NULL)
226    return EGL_NO_CONTEXT;
227
228  DCHECK(command_buffer_ != NULL);
229  DCHECK(transfer_buffer_.get());
230
231  bool bind_generates_resources = true;
232
233  context_.reset(new gpu::gles2::GLES2Implementation(
234      gles2_cmd_helper_.get(),
235      NULL,
236      transfer_buffer_.get(),
237      bind_generates_resources,
238      gpu_control_.get()));
239
240  if (!context_->Initialize(
241      kTransferBufferSize,
242      kTransferBufferSize / 2,
243      kTransferBufferSize * 2,
244      gpu::gles2::GLES2Implementation::kNoLimit)) {
245    return EGL_NO_CONTEXT;
246  }
247
248  context_->EnableFeatureCHROMIUM("pepper3d_allow_buffers_on_multiple_targets");
249  context_->EnableFeatureCHROMIUM("pepper3d_support_fixed_attribs");
250
251  return context_.get();
252}
253
254void Display::DestroyContext(EGLContext ctx) {
255  DCHECK(IsValidContext(ctx));
256  context_.reset();
257  transfer_buffer_.reset();
258}
259
260bool Display::MakeCurrent(EGLSurface draw, EGLSurface read, EGLContext ctx) {
261  if (ctx == EGL_NO_CONTEXT) {
262    gles2::SetGLContext(NULL);
263  } else {
264    DCHECK(IsValidSurface(draw));
265    DCHECK(IsValidSurface(read));
266    DCHECK(IsValidContext(ctx));
267    gles2::SetGLContext(context_.get());
268  }
269  return true;
270}
271
272}  // namespace egl
273