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