Home | History | Annotate | Download | only in gpu
      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 "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
      6 
      7 #include <GLES2/gl2.h>
      8 #ifndef GL_GLEXT_PROTOTYPES
      9 #define GL_GLEXT_PROTOTYPES 1
     10 #endif
     11 #include <GLES2/gl2ext.h>
     12 #include <GLES2/gl2extchromium.h>
     13 
     14 #include <string>
     15 
     16 #include "base/atomicops.h"
     17 #include "base/bind.h"
     18 #include "base/bind_helpers.h"
     19 #include "base/callback.h"
     20 #include "base/lazy_instance.h"
     21 #include "base/logging.h"
     22 #include "gpu/command_buffer/client/gles2_implementation.h"
     23 #include "gpu/command_buffer/client/gles2_lib.h"
     24 #include "gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h"
     25 #include "ui/gfx/size.h"
     26 #include "ui/gl/gl_implementation.h"
     27 
     28 using gpu::gles2::GLES2Implementation;
     29 using gpu::GLInProcessContext;
     30 
     31 namespace webkit {
     32 namespace gpu {
     33 
     34 namespace {
     35 
     36 const int32 kCommandBufferSize = 1024 * 1024;
     37 // TODO(kbr): make the transfer buffer size configurable via context
     38 // creation attributes.
     39 const size_t kStartTransferBufferSize = 4 * 1024 * 1024;
     40 const size_t kMinTransferBufferSize = 1 * 256 * 1024;
     41 const size_t kMaxTransferBufferSize = 16 * 1024 * 1024;
     42 
     43 // Singleton used to initialize and terminate the gles2 library.
     44 class GLES2Initializer {
     45  public:
     46   GLES2Initializer() {
     47     ::gles2::Initialize();
     48   }
     49 
     50   ~GLES2Initializer() {
     51     ::gles2::Terminate();
     52   }
     53 
     54  private:
     55   DISALLOW_COPY_AND_ASSIGN(GLES2Initializer);
     56 };
     57 
     58 static base::LazyInstance<GLES2Initializer> g_gles2_initializer =
     59     LAZY_INSTANCE_INITIALIZER;
     60 
     61 }  // namespace anonymous
     62 
     63 // static
     64 scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
     65 WebGraphicsContext3DInProcessCommandBufferImpl::CreateViewContext(
     66     const blink::WebGraphicsContext3D::Attributes& attributes,
     67     bool lose_context_when_out_of_memory,
     68     gfx::AcceleratedWidget window) {
     69   DCHECK_NE(gfx::GetGLImplementation(), gfx::kGLImplementationNone);
     70   bool is_offscreen = false;
     71   return make_scoped_ptr(new WebGraphicsContext3DInProcessCommandBufferImpl(
     72       scoped_ptr< ::gpu::GLInProcessContext>(),
     73       attributes,
     74       lose_context_when_out_of_memory,
     75       is_offscreen,
     76       window));
     77 }
     78 
     79 // static
     80 scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
     81 WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext(
     82     const blink::WebGraphicsContext3D::Attributes& attributes,
     83     bool lose_context_when_out_of_memory) {
     84   bool is_offscreen = true;
     85   return make_scoped_ptr(new WebGraphicsContext3DInProcessCommandBufferImpl(
     86       scoped_ptr< ::gpu::GLInProcessContext>(),
     87       attributes,
     88       lose_context_when_out_of_memory,
     89       is_offscreen,
     90       gfx::kNullAcceleratedWidget));
     91 }
     92 
     93 scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
     94 WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
     95     scoped_ptr< ::gpu::GLInProcessContext> context,
     96     const blink::WebGraphicsContext3D::Attributes& attributes) {
     97   bool lose_context_when_out_of_memory = false;  // Not used.
     98   bool is_offscreen = true;                      // Not used.
     99   return make_scoped_ptr(new WebGraphicsContext3DInProcessCommandBufferImpl(
    100       context.Pass(),
    101       attributes,
    102       lose_context_when_out_of_memory,
    103       is_offscreen,
    104       gfx::kNullAcceleratedWidget /* window. Not used. */));
    105 }
    106 
    107 WebGraphicsContext3DInProcessCommandBufferImpl::
    108     WebGraphicsContext3DInProcessCommandBufferImpl(
    109         scoped_ptr< ::gpu::GLInProcessContext> context,
    110         const blink::WebGraphicsContext3D::Attributes& attributes,
    111         bool lose_context_when_out_of_memory,
    112         bool is_offscreen,
    113         gfx::AcceleratedWidget window)
    114     : share_resources_(attributes.shareResources),
    115       webgl_context_(attributes.noExtensions),
    116       is_offscreen_(is_offscreen),
    117       window_(window),
    118       context_(context.Pass()) {
    119   ConvertAttributes(attributes, &attribs_);
    120   attribs_.lose_context_when_out_of_memory = lose_context_when_out_of_memory;
    121 }
    122 
    123 WebGraphicsContext3DInProcessCommandBufferImpl::
    124     ~WebGraphicsContext3DInProcessCommandBufferImpl() {
    125 }
    126 
    127 // static
    128 void WebGraphicsContext3DInProcessCommandBufferImpl::ConvertAttributes(
    129     const blink::WebGraphicsContext3D::Attributes& attributes,
    130     ::gpu::GLInProcessContextAttribs* output_attribs) {
    131   output_attribs->alpha_size = attributes.alpha ? 8 : 0;
    132   output_attribs->depth_size = attributes.depth ? 24 : 0;
    133   output_attribs->stencil_size = attributes.stencil ? 8 : 0;
    134   output_attribs->samples = attributes.antialias ? 4 : 0;
    135   output_attribs->sample_buffers = attributes.antialias ? 1 : 0;
    136   output_attribs->fail_if_major_perf_caveat =
    137       attributes.failIfMajorPerformanceCaveat ? 1 : 0;
    138 }
    139 
    140 bool WebGraphicsContext3DInProcessCommandBufferImpl::MaybeInitializeGL() {
    141   if (initialized_)
    142     return true;
    143 
    144   if (initialize_failed_)
    145     return false;
    146 
    147   // Ensure the gles2 library is initialized first in a thread safe way.
    148   g_gles2_initializer.Get();
    149 
    150   if (!context_) {
    151     // TODO(kbr): More work will be needed in this implementation to
    152     // properly support GPU switching. Like in the out-of-process
    153     // command buffer implementation, all previously created contexts
    154     // will need to be lost either when the first context requesting the
    155     // discrete GPU is created, or the last one is destroyed.
    156     gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
    157     context_.reset(GLInProcessContext::Create(NULL, /* service */
    158                                               NULL, /* surface */
    159                                               is_offscreen_,
    160                                               window_,
    161                                               gfx::Size(1, 1),
    162                                               NULL, /* share_context */
    163                                               share_resources_,
    164                                               attribs_,
    165                                               gpu_preference));
    166   }
    167 
    168   if (context_) {
    169     base::Closure context_lost_callback = base::Bind(
    170         &WebGraphicsContext3DInProcessCommandBufferImpl::OnContextLost,
    171         base::Unretained(this));
    172     context_->SetContextLostCallback(context_lost_callback);
    173   } else {
    174     initialize_failed_ = true;
    175     return false;
    176   }
    177 
    178   real_gl_ = context_->GetImplementation();
    179   setGLInterface(real_gl_);
    180 
    181   if (real_gl_ && webgl_context_)
    182     real_gl_->EnableFeatureCHROMIUM("webgl_enable_glsl_webgl_validation");
    183 
    184   initialized_ = true;
    185   return true;
    186 }
    187 
    188 bool WebGraphicsContext3DInProcessCommandBufferImpl::makeContextCurrent() {
    189   if (!MaybeInitializeGL())
    190     return false;
    191   ::gles2::SetGLContext(GetGLInterface());
    192   return context_ && !isContextLost();
    193 }
    194 
    195 bool WebGraphicsContext3DInProcessCommandBufferImpl::isContextLost() {
    196   return context_lost_reason_ != GL_NO_ERROR;
    197 }
    198 
    199 WGC3Denum WebGraphicsContext3DInProcessCommandBufferImpl::
    200     getGraphicsResetStatusARB() {
    201   return context_lost_reason_;
    202 }
    203 
    204 ::gpu::ContextSupport*
    205 WebGraphicsContext3DInProcessCommandBufferImpl::GetContextSupport() {
    206   return real_gl_;
    207 }
    208 
    209 void WebGraphicsContext3DInProcessCommandBufferImpl::OnContextLost() {
    210   // TODO(kbr): improve the precision here.
    211   context_lost_reason_ = GL_UNKNOWN_CONTEXT_RESET_ARB;
    212   if (context_lost_callback_) {
    213     context_lost_callback_->onContextLost();
    214   }
    215 }
    216 
    217 }  // namespace gpu
    218 }  // namespace webkit
    219