Home | History | Annotate | Download | only in egl
      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 
     18 namespace {
     19 const int32 kCommandBufferSize = 1024 * 1024;
     20 const int32 kTransferBufferSize = 512 * 1024;
     21 }
     22 
     23 namespace egl {
     24 
     25 Display::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 
     33 Display::~Display() {
     34   gles2::Terminate();
     35 }
     36 
     37 bool Display::Initialize() {
     38   gles2::Initialize();
     39   is_initialized_ = true;
     40   return true;
     41 }
     42 
     43 bool Display::IsValidConfig(EGLConfig config) {
     44   return (config != NULL) && (config == config_.get());
     45 }
     46 
     47 bool 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 
     62 bool 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 
     77 bool 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 
     84 bool 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 
     93 bool Display::IsValidSurface(EGLSurface surface) {
     94   return (surface != NULL) && (surface == surface_.get());
     95 }
     96 
     97 EGLSurface 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, 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(size);
    130     create_offscreen_ = false;
    131     create_offscreen_width_ = 0;
    132     create_offscreen_height_ = 0;
    133   } else {
    134     gl_surface_ = gfx::GLSurface::CreateViewGLSurface(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_.get());
    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 
    196 void 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 
    208 void Display::SwapBuffers(EGLSurface surface) {
    209   DCHECK(IsValidSurface(surface));
    210   context_->SwapBuffers();
    211 }
    212 
    213 bool Display::IsValidContext(EGLContext ctx) {
    214   return (ctx != NULL) && (ctx == context_.get());
    215 }
    216 
    217 EGLContext 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   context_.reset(new gpu::gles2::GLES2Implementation(
    228       gles2_cmd_helper_.get(),
    229       NULL,
    230       transfer_buffer_.get(),
    231       true,
    232       NULL));
    233 
    234   if (!context_->Initialize(
    235       kTransferBufferSize,
    236       kTransferBufferSize / 2,
    237       kTransferBufferSize * 2)) {
    238     return EGL_NO_CONTEXT;
    239   }
    240 
    241   context_->EnableFeatureCHROMIUM("pepper3d_allow_buffers_on_multiple_targets");
    242   context_->EnableFeatureCHROMIUM("pepper3d_support_fixed_attribs");
    243 
    244   return context_.get();
    245 }
    246 
    247 void Display::DestroyContext(EGLContext ctx) {
    248   DCHECK(IsValidContext(ctx));
    249   context_.reset();
    250   transfer_buffer_.reset();
    251 }
    252 
    253 bool Display::MakeCurrent(EGLSurface draw, EGLSurface read, EGLContext ctx) {
    254   if (ctx == EGL_NO_CONTEXT) {
    255     gles2::SetGLContext(NULL);
    256   } else {
    257     DCHECK(IsValidSurface(draw));
    258     DCHECK(IsValidSurface(read));
    259     DCHECK(IsValidContext(ctx));
    260     gles2::SetGLContext(context_.get());
    261   }
    262   return true;
    263 }
    264 
    265 }  // namespace egl
    266