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