display.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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_lib.h"
11#include "gpu/command_buffer/client/transfer_buffer.h"
12#include "gpu/command_buffer/service/context_group.h"
13#include "gpu/command_buffer/service/transfer_buffer_manager.h"
14#include "gpu/gles2_conform_support/egl/config.h"
15#include "gpu/gles2_conform_support/egl/surface.h"
16
17namespace {
18const int32 kCommandBufferSize = 1024 * 1024;
19const int32 kTransferBufferSize = 512 * 1024;
20}
21
22namespace egl {
23
24Display::Display(EGLNativeDisplayType display_id)
25    : display_id_(display_id),
26      is_initialized_(false),
27      create_offscreen_(false),
28      create_offscreen_width_(0),
29      create_offscreen_height_(0) {
30}
31
32Display::~Display() {
33  gles2::Terminate();
34}
35
36bool Display::Initialize() {
37  gles2::Initialize();
38  is_initialized_ = true;
39  return true;
40}
41
42bool Display::IsValidConfig(EGLConfig config) {
43  return (config != NULL) && (config == config_.get());
44}
45
46bool Display::ChooseConfigs(EGLConfig* configs,
47                            EGLint config_size,
48                            EGLint* num_config) {
49  // TODO(alokp): Find out a way to find all configs. CommandBuffer currently
50  // does not support finding or choosing configs.
51  *num_config = 1;
52  if (configs != NULL) {
53    if (config_ == NULL) {
54      config_.reset(new Config);
55    }
56    configs[0] = config_.get();
57  }
58  return true;
59}
60
61bool Display::GetConfigs(EGLConfig* configs,
62                         EGLint config_size,
63                         EGLint* num_config) {
64  // TODO(alokp): Find out a way to find all configs. CommandBuffer currently
65  // does not support finding or choosing configs.
66  *num_config = 1;
67  if (configs != NULL) {
68    if (config_ == NULL) {
69      config_.reset(new Config);
70    }
71    configs[0] = config_.get();
72  }
73  return true;
74}
75
76bool Display::GetConfigAttrib(EGLConfig config,
77                              EGLint attribute,
78                              EGLint* value) {
79  const egl::Config* cfg = static_cast<egl::Config*>(config);
80  return cfg->GetAttrib(attribute, value);
81}
82
83bool Display::IsValidNativeWindow(EGLNativeWindowType win) {
84#if defined OS_WIN
85  return ::IsWindow(win) != FALSE;
86#else
87  // TODO(alokp): Validate window handle.
88  return true;
89#endif  // OS_WIN
90}
91
92bool Display::IsValidSurface(EGLSurface surface) {
93  return (surface != NULL) && (surface == surface_.get());
94}
95
96EGLSurface Display::CreateWindowSurface(EGLConfig config,
97                                        EGLNativeWindowType win,
98                                        const EGLint* attrib_list) {
99  if (surface_ != NULL) {
100    // We do not support more than one window surface.
101    return EGL_NO_SURFACE;
102  }
103
104  {
105    gpu::TransferBufferManager* manager = new gpu::TransferBufferManager();
106    transfer_buffer_manager_.reset(manager);
107    manager->Initialize();
108  }
109  scoped_ptr<gpu::CommandBufferService> command_buffer(
110      new gpu::CommandBufferService(transfer_buffer_manager_.get()));
111  if (!command_buffer->Initialize())
112    return NULL;
113
114  gpu::gles2::ContextGroup::Ref group(new gpu::gles2::ContextGroup(NULL,
115                                                                   NULL,
116                                                                   NULL,
117                                                                   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(false, size);
131    create_offscreen_ = false;
132    create_offscreen_width_ = 0;
133    create_offscreen_height_ = 0;
134  } else {
135    gl_surface_ = gfx::GLSurface::CreateViewGLSurface(false, 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_);
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                            NULL,
170                            attribs)) {
171    return EGL_NO_SURFACE;
172  }
173
174  command_buffer->SetPutOffsetChangeCallback(
175      base::Bind(&gpu::GpuScheduler::PutChanged,
176                 base::Unretained(gpu_scheduler_.get())));
177  command_buffer->SetGetBufferChangeCallback(
178      base::Bind(&gpu::GpuScheduler::SetGetBuffer,
179                 base::Unretained(gpu_scheduler_.get())));
180
181  scoped_ptr<gpu::gles2::GLES2CmdHelper> cmd_helper(
182      new gpu::gles2::GLES2CmdHelper(command_buffer.get()));
183  if (!cmd_helper->Initialize(kCommandBufferSize))
184    return NULL;
185
186  scoped_ptr<gpu::TransferBuffer> transfer_buffer(new gpu::TransferBuffer(
187      cmd_helper.get()));
188
189  command_buffer_.reset(command_buffer.release());
190  transfer_buffer_.reset(transfer_buffer.release());
191  gles2_cmd_helper_.reset(cmd_helper.release());
192  surface_.reset(new Surface(win));
193
194  return surface_.get();
195}
196
197void Display::DestroySurface(EGLSurface surface) {
198  DCHECK(IsValidSurface(surface));
199  gpu_scheduler_.reset();
200  if (decoder_.get()) {
201    decoder_->Destroy(true);
202  }
203  decoder_.reset();
204  gl_surface_ = NULL;
205  gl_context_ = NULL;
206  surface_.reset();
207}
208
209void Display::SwapBuffers(EGLSurface surface) {
210  DCHECK(IsValidSurface(surface));
211  context_->SwapBuffers();
212}
213
214bool Display::IsValidContext(EGLContext ctx) {
215  return (ctx != NULL) && (ctx == context_.get());
216}
217
218EGLContext Display::CreateContext(EGLConfig config,
219                                  EGLContext share_ctx,
220                                  const EGLint* attrib_list) {
221  DCHECK(IsValidConfig(config));
222  // TODO(alokp): Add support for shared contexts.
223  if (share_ctx != NULL)
224    return EGL_NO_CONTEXT;
225
226  DCHECK(command_buffer_ != NULL);
227  DCHECK(transfer_buffer_.get());
228  bool share_resources = share_ctx != NULL;
229  context_.reset(new gpu::gles2::GLES2Implementation(
230      gles2_cmd_helper_.get(),
231      NULL,
232      transfer_buffer_.get(),
233      share_resources,
234      true));
235
236  if (!context_->Initialize(
237      kTransferBufferSize,
238      kTransferBufferSize / 2,
239      kTransferBufferSize * 2)) {
240    return EGL_NO_CONTEXT;
241  }
242
243  context_->EnableFeatureCHROMIUM("pepper3d_allow_buffers_on_multiple_targets");
244  context_->EnableFeatureCHROMIUM("pepper3d_support_fixed_attribs");
245
246  return context_.get();
247}
248
249void Display::DestroyContext(EGLContext ctx) {
250  DCHECK(IsValidContext(ctx));
251  context_.reset();
252  transfer_buffer_.reset();
253}
254
255bool Display::MakeCurrent(EGLSurface draw, EGLSurface read, EGLContext ctx) {
256  if (ctx == EGL_NO_CONTEXT) {
257    gles2::SetGLContext(NULL);
258  } else {
259    DCHECK(IsValidSurface(draw));
260    DCHECK(IsValidSurface(read));
261    DCHECK(IsValidContext(ctx));
262    gles2::SetGLContext(context_.get());
263  }
264  return true;
265}
266
267}  // namespace egl
268