display.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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  gpu_control_.reset(
127      new gpu::GpuControlService(NULL, NULL, group->mailbox_manager(), NULL));
128
129  decoder_->set_engine(gpu_scheduler_.get());
130  gfx::Size size(create_offscreen_width_, create_offscreen_height_);
131  if (create_offscreen_) {
132    gl_surface_ = gfx::GLSurface::CreateOffscreenGLSurface(size);
133    create_offscreen_ = false;
134    create_offscreen_width_ = 0;
135    create_offscreen_height_ = 0;
136  } else {
137    gl_surface_ = gfx::GLSurface::CreateViewGLSurface(win);
138  }
139  if (!gl_surface_.get())
140    return EGL_NO_SURFACE;
141
142  gl_context_ = gfx::GLContext::CreateGLContext(NULL,
143                                                gl_surface_.get(),
144                                                gfx::PreferDiscreteGpu);
145  if (!gl_context_.get())
146    return EGL_NO_SURFACE;
147
148  gl_context_->MakeCurrent(gl_surface_.get());
149
150  EGLint depth_size = 0;
151  EGLint alpha_size = 0;
152  EGLint stencil_size = 0;
153  GetConfigAttrib(config, EGL_DEPTH_SIZE, &depth_size);
154  GetConfigAttrib(config, EGL_ALPHA_SIZE, &alpha_size);
155  GetConfigAttrib(config, EGL_STENCIL_SIZE, &stencil_size);
156  std::vector<int32> attribs;
157  attribs.push_back(EGL_DEPTH_SIZE);
158  attribs.push_back(depth_size);
159  attribs.push_back(EGL_ALPHA_SIZE);
160  attribs.push_back(alpha_size);
161  attribs.push_back(EGL_STENCIL_SIZE);
162  attribs.push_back(stencil_size);
163  // TODO(gman): Insert attrib_list. Although ES 1.1 says it must be null
164  attribs.push_back(EGL_NONE);
165
166  if (!decoder_->Initialize(gl_surface_.get(),
167                            gl_context_.get(),
168                            gl_surface_->IsOffscreen(),
169                            size,
170                            gpu::gles2::DisallowedFeatures(),
171                            attribs)) {
172    return EGL_NO_SURFACE;
173  }
174
175  command_buffer->SetPutOffsetChangeCallback(
176      base::Bind(&gpu::GpuScheduler::PutChanged,
177                 base::Unretained(gpu_scheduler_.get())));
178  command_buffer->SetGetBufferChangeCallback(
179      base::Bind(&gpu::GpuScheduler::SetGetBuffer,
180                 base::Unretained(gpu_scheduler_.get())));
181
182  scoped_ptr<gpu::gles2::GLES2CmdHelper> cmd_helper(
183      new gpu::gles2::GLES2CmdHelper(command_buffer.get()));
184  if (!cmd_helper->Initialize(kCommandBufferSize))
185    return NULL;
186
187  scoped_ptr<gpu::TransferBuffer> transfer_buffer(new gpu::TransferBuffer(
188      cmd_helper.get()));
189
190  command_buffer_.reset(command_buffer.release());
191  transfer_buffer_.reset(transfer_buffer.release());
192  gles2_cmd_helper_.reset(cmd_helper.release());
193  surface_.reset(new Surface(win));
194
195  return surface_.get();
196}
197
198void Display::DestroySurface(EGLSurface surface) {
199  DCHECK(IsValidSurface(surface));
200  gpu_scheduler_.reset();
201  if (decoder_.get()) {
202    decoder_->Destroy(true);
203  }
204  decoder_.reset();
205  gl_surface_ = NULL;
206  gl_context_ = NULL;
207  surface_.reset();
208}
209
210void Display::SwapBuffers(EGLSurface surface) {
211  DCHECK(IsValidSurface(surface));
212  context_->SwapBuffers();
213}
214
215bool Display::IsValidContext(EGLContext ctx) {
216  return (ctx != NULL) && (ctx == context_.get());
217}
218
219EGLContext Display::CreateContext(EGLConfig config,
220                                  EGLContext share_ctx,
221                                  const EGLint* attrib_list) {
222  DCHECK(IsValidConfig(config));
223  // TODO(alokp): Add support for shared contexts.
224  if (share_ctx != NULL)
225    return EGL_NO_CONTEXT;
226
227  DCHECK(command_buffer_ != NULL);
228  DCHECK(transfer_buffer_.get());
229  context_.reset(new gpu::gles2::GLES2Implementation(
230      gles2_cmd_helper_.get(),
231      NULL,
232      transfer_buffer_.get(),
233      true,
234      gpu_control_.get()));
235
236  if (!context_->Initialize(
237      kTransferBufferSize,
238      kTransferBufferSize / 2,
239      kTransferBufferSize * 2,
240      gpu::gles2::GLES2Implementation::kNoLimit)) {
241    return EGL_NO_CONTEXT;
242  }
243
244  context_->EnableFeatureCHROMIUM("pepper3d_allow_buffers_on_multiple_targets");
245  context_->EnableFeatureCHROMIUM("pepper3d_support_fixed_attribs");
246
247  return context_.get();
248}
249
250void Display::DestroyContext(EGLContext ctx) {
251  DCHECK(IsValidContext(ctx));
252  context_.reset();
253  transfer_buffer_.reset();
254}
255
256bool Display::MakeCurrent(EGLSurface draw, EGLSurface read, EGLContext ctx) {
257  if (ctx == EGL_NO_CONTEXT) {
258    gles2::SetGLContext(NULL);
259  } else {
260    DCHECK(IsValidSurface(draw));
261    DCHECK(IsValidSurface(read));
262    DCHECK(IsValidContext(ctx));
263    gles2::SetGLContext(context_.get());
264  }
265  return true;
266}
267
268}  // namespace egl
269