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/mailbox_manager.h"
15#include "gpu/command_buffer/service/memory_tracking.h"
16#include "gpu/command_buffer/service/transfer_buffer_manager.h"
17#include "gpu/gles2_conform_support/egl/config.h"
18#include "gpu/gles2_conform_support/egl/surface.h"
19
20namespace {
21const int32 kCommandBufferSize = 1024 * 1024;
22const int32 kTransferBufferSize = 512 * 1024;
23}
24
25namespace egl {
26
27Display::Display(EGLNativeDisplayType display_id)
28    : display_id_(display_id),
29      is_initialized_(false),
30      create_offscreen_(false),
31      create_offscreen_width_(0),
32      create_offscreen_height_(0) {
33}
34
35Display::~Display() {
36  gles2::Terminate();
37}
38
39bool Display::Initialize() {
40  gles2::Initialize();
41  is_initialized_ = true;
42  return true;
43}
44
45bool Display::IsValidConfig(EGLConfig config) {
46  return (config != NULL) && (config == config_.get());
47}
48
49bool Display::ChooseConfigs(EGLConfig* configs,
50                            EGLint config_size,
51                            EGLint* num_config) {
52  // TODO(alokp): Find out a way to find all configs. CommandBuffer currently
53  // does not support finding or choosing configs.
54  *num_config = 1;
55  if (configs != NULL) {
56    if (config_ == NULL) {
57      config_.reset(new Config);
58    }
59    configs[0] = config_.get();
60  }
61  return true;
62}
63
64bool Display::GetConfigs(EGLConfig* configs,
65                         EGLint config_size,
66                         EGLint* num_config) {
67  // TODO(alokp): Find out a way to find all configs. CommandBuffer currently
68  // does not support finding or choosing configs.
69  *num_config = 1;
70  if (configs != NULL) {
71    if (config_ == NULL) {
72      config_.reset(new Config);
73    }
74    configs[0] = config_.get();
75  }
76  return true;
77}
78
79bool Display::GetConfigAttrib(EGLConfig config,
80                              EGLint attribute,
81                              EGLint* value) {
82  const egl::Config* cfg = static_cast<egl::Config*>(config);
83  return cfg->GetAttrib(attribute, value);
84}
85
86bool Display::IsValidNativeWindow(EGLNativeWindowType win) {
87#if defined OS_WIN
88  return ::IsWindow(win) != FALSE;
89#else
90  // TODO(alokp): Validate window handle.
91  return true;
92#endif  // OS_WIN
93}
94
95bool Display::IsValidSurface(EGLSurface surface) {
96  return (surface != NULL) && (surface == surface_.get());
97}
98
99EGLSurface Display::CreateWindowSurface(EGLConfig config,
100                                        EGLNativeWindowType win,
101                                        const EGLint* attrib_list) {
102  if (surface_ != NULL) {
103    // We do not support more than one window surface.
104    return EGL_NO_SURFACE;
105  }
106
107  {
108    gpu::TransferBufferManager* manager = new gpu::TransferBufferManager();
109    transfer_buffer_manager_.reset(manager);
110    manager->Initialize();
111  }
112  scoped_ptr<gpu::CommandBufferService> command_buffer(
113      new gpu::CommandBufferService(transfer_buffer_manager_.get()));
114  if (!command_buffer->Initialize())
115    return NULL;
116
117  scoped_refptr<gpu::gles2::ContextGroup> group(new gpu::gles2::ContextGroup(
118      NULL, NULL, new gpu::gles2::ShaderTranslatorCache, NULL, true));
119
120  decoder_.reset(gpu::gles2::GLES2Decoder::Create(group.get()));
121  if (!decoder_.get())
122    return EGL_NO_SURFACE;
123
124  gpu_scheduler_.reset(new gpu::GpuScheduler(command_buffer.get(),
125                                             decoder_.get(),
126                                             NULL));
127
128  decoder_->set_engine(gpu_scheduler_.get());
129  gfx::Size size(create_offscreen_width_, create_offscreen_height_);
130  if (create_offscreen_) {
131    gl_surface_ = gfx::GLSurface::CreateOffscreenGLSurface(size);
132    create_offscreen_ = false;
133    create_offscreen_width_ = 0;
134    create_offscreen_height_ = 0;
135  } else {
136    gl_surface_ = gfx::GLSurface::CreateViewGLSurface(win);
137  }
138  if (!gl_surface_.get())
139    return EGL_NO_SURFACE;
140
141  gl_context_ = gfx::GLContext::CreateGLContext(NULL,
142                                                gl_surface_.get(),
143                                                gfx::PreferDiscreteGpu);
144  if (!gl_context_.get())
145    return EGL_NO_SURFACE;
146
147  gl_context_->MakeCurrent(gl_surface_.get());
148
149  EGLint depth_size = 0;
150  EGLint alpha_size = 0;
151  EGLint stencil_size = 0;
152  GetConfigAttrib(config, EGL_DEPTH_SIZE, &depth_size);
153  GetConfigAttrib(config, EGL_ALPHA_SIZE, &alpha_size);
154  GetConfigAttrib(config, EGL_STENCIL_SIZE, &stencil_size);
155  std::vector<int32> attribs;
156  attribs.push_back(EGL_DEPTH_SIZE);
157  attribs.push_back(depth_size);
158  attribs.push_back(EGL_ALPHA_SIZE);
159  attribs.push_back(alpha_size);
160  attribs.push_back(EGL_STENCIL_SIZE);
161  attribs.push_back(stencil_size);
162  // TODO(gman): Insert attrib_list. Although ES 1.1 says it must be null
163  attribs.push_back(EGL_NONE);
164
165  if (!decoder_->Initialize(gl_surface_.get(),
166                            gl_context_.get(),
167                            gl_surface_->IsOffscreen(),
168                            size,
169                            gpu::gles2::DisallowedFeatures(),
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
229  bool bind_generates_resources = true;
230  bool lose_context_when_out_of_memory = false;
231
232  context_.reset(
233      new gpu::gles2::GLES2Implementation(gles2_cmd_helper_.get(),
234                                          NULL,
235                                          transfer_buffer_.get(),
236                                          bind_generates_resources,
237                                          lose_context_when_out_of_memory,
238                                          this));
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
272gpu::Capabilities Display::GetCapabilities() {
273  return decoder_->GetCapabilities();
274}
275
276gfx::GpuMemoryBuffer* Display::CreateGpuMemoryBuffer(
277    size_t width,
278    size_t height,
279    unsigned internalformat,
280    unsigned usage,
281    int32* id) {
282  NOTIMPLEMENTED();
283  return NULL;
284}
285
286void Display::DestroyGpuMemoryBuffer(int32 id) {
287  NOTIMPLEMENTED();
288}
289
290uint32 Display::InsertSyncPoint() {
291  NOTIMPLEMENTED();
292  return 0u;
293}
294
295uint32 Display::InsertFutureSyncPoint() {
296  NOTIMPLEMENTED();
297  return 0u;
298}
299
300void Display::RetireSyncPoint(uint32 sync_point) {
301  NOTIMPLEMENTED();
302}
303
304void Display::SignalSyncPoint(uint32 sync_point,
305                              const base::Closure& callback) {
306  NOTIMPLEMENTED();
307}
308
309void Display::SignalQuery(uint32 query, const base::Closure& callback) {
310  NOTIMPLEMENTED();
311}
312
313void Display::SetSurfaceVisible(bool visible) {
314  NOTIMPLEMENTED();
315}
316
317void Display::Echo(const base::Closure& callback) {
318  NOTIMPLEMENTED();
319}
320
321uint32 Display::CreateStreamTexture(uint32 texture_id) {
322  NOTIMPLEMENTED();
323  return 0;
324}
325
326}  // namespace egl
327