// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ui/gl/gl_surface.h" #include #include #include "base/command_line.h" #include "base/lazy_instance.h" #include "base/logging.h" #include "base/threading/thread_local.h" #include "base/trace_event/trace_event.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_switches.h" #if defined(USE_X11) #include #endif namespace gfx { namespace { base::LazyInstance >::Leaky current_surface_ = LAZY_INSTANCE_INITIALIZER; } // namespace // static bool GLSurface::InitializeOneOff() { DCHECK_EQ(kGLImplementationNone, GetGLImplementation()); TRACE_EVENT0("gpu", "GLSurface::InitializeOneOff"); std::vector allowed_impls; GetAllowedGLImplementations(&allowed_impls); DCHECK(!allowed_impls.empty()); base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); // The default implementation is always the first one in list. GLImplementation impl = allowed_impls[0]; bool fallback_to_osmesa = false; if (cmd->HasSwitch(switches::kOverrideUseGLWithOSMesaForTests)) { impl = kGLImplementationOSMesaGL; } else if (cmd->HasSwitch(switches::kUseGL)) { std::string requested_implementation_name = cmd->GetSwitchValueASCII(switches::kUseGL); if (requested_implementation_name == "any") { fallback_to_osmesa = true; } else if (requested_implementation_name == "swiftshader") { impl = kGLImplementationEGLGLES2; } else { impl = GetNamedGLImplementation(requested_implementation_name); if (std::find(allowed_impls.begin(), allowed_impls.end(), impl) == allowed_impls.end()) { LOG(ERROR) << "Requested GL implementation is not available."; return false; } } } bool gpu_service_logging = cmd->HasSwitch(switches::kEnableGPUServiceLogging); bool disable_gl_drawing = cmd->HasSwitch(switches::kDisableGLDrawingForTests); return InitializeOneOffImplementation( impl, fallback_to_osmesa, gpu_service_logging, disable_gl_drawing); } // static bool GLSurface::InitializeOneOffImplementation(GLImplementation impl, bool fallback_to_osmesa, bool gpu_service_logging, bool disable_gl_drawing) { bool initialized = InitializeStaticGLBindings(impl) && InitializeOneOffInternal(); if (!initialized && fallback_to_osmesa) { ClearGLBindings(); initialized = InitializeStaticGLBindings(kGLImplementationOSMesaGL) && InitializeOneOffInternal(); } if (!initialized) ClearGLBindings(); if (initialized) { DVLOG(1) << "Using " << GetGLImplementationName(GetGLImplementation()) << " GL implementation."; if (gpu_service_logging) InitializeDebugGLBindings(); if (disable_gl_drawing) InitializeNullDrawGLBindings(); } return initialized; } // static void GLSurface::InitializeOneOffForTests() { DCHECK_EQ(kGLImplementationNone, GetGLImplementation()); #if defined(USE_X11) XInitThreads(); #endif bool use_osmesa = true; // We usually use OSMesa as this works on all bots. The command line can // override this behaviour to use hardware GL. if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kUseGpuInTests)) use_osmesa = false; #if defined(OS_ANDROID) // On Android we always use hardware GL. use_osmesa = false; #endif std::vector allowed_impls; GetAllowedGLImplementations(&allowed_impls); DCHECK(!allowed_impls.empty()); GLImplementation impl = allowed_impls[0]; if (use_osmesa) impl = kGLImplementationOSMesaGL; DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL)) << "kUseGL has not effect in tests"; bool fallback_to_osmesa = false; bool gpu_service_logging = false; bool disable_gl_drawing = true; CHECK(InitializeOneOffImplementation( impl, fallback_to_osmesa, gpu_service_logging, disable_gl_drawing)); } // static void GLSurface::InitializeOneOffWithMockBindingsForTests() { DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL)) << "kUseGL has not effect in tests"; // This method may be called multiple times in the same process to set up // mock bindings in different ways. ClearGLBindings(); bool fallback_to_osmesa = false; bool gpu_service_logging = false; bool disable_gl_drawing = false; CHECK(InitializeOneOffImplementation(kGLImplementationMockGL, fallback_to_osmesa, gpu_service_logging, disable_gl_drawing)); } // static void GLSurface::InitializeDynamicMockBindingsForTests(GLContext* context) { CHECK(InitializeDynamicGLBindings(kGLImplementationMockGL, context)); } GLSurface::GLSurface() {} bool GLSurface::Initialize() { return true; } void GLSurface::DestroyAndTerminateDisplay() { Destroy(); } bool GLSurface::Resize(const gfx::Size& size) { NOTIMPLEMENTED(); return false; } bool GLSurface::Recreate() { NOTIMPLEMENTED(); return false; } bool GLSurface::DeferDraws() { return false; } bool GLSurface::SupportsPostSubBuffer() { return false; } unsigned int GLSurface::GetBackingFrameBufferObject() { return 0; } bool GLSurface::SwapBuffersAsync(const SwapCompletionCallback& callback) { DCHECK(!IsSurfaceless()); bool success = SwapBuffers(); callback.Run(); return success; } bool GLSurface::PostSubBuffer(int x, int y, int width, int height) { return false; } bool GLSurface::PostSubBufferAsync(int x, int y, int width, int height, const SwapCompletionCallback& callback) { bool success = PostSubBuffer(x, y, width, height); callback.Run(); return success; } bool GLSurface::OnMakeCurrent(GLContext* context) { return true; } void GLSurface::NotifyWasBound() { } bool GLSurface::SetBackbufferAllocation(bool allocated) { return true; } void GLSurface::SetFrontbufferAllocation(bool allocated) { } void* GLSurface::GetShareHandle() { NOTIMPLEMENTED(); return NULL; } void* GLSurface::GetDisplay() { NOTIMPLEMENTED(); return NULL; } void* GLSurface::GetConfig() { NOTIMPLEMENTED(); return NULL; } unsigned GLSurface::GetFormat() { NOTIMPLEMENTED(); return 0; } VSyncProvider* GLSurface::GetVSyncProvider() { return NULL; } bool GLSurface::ScheduleOverlayPlane(int z_order, OverlayTransform transform, GLImage* image, const Rect& bounds_rect, const RectF& crop_rect) { NOTIMPLEMENTED(); return false; } bool GLSurface::IsSurfaceless() const { return false; } GLSurface* GLSurface::GetCurrent() { return current_surface_.Pointer()->Get(); } GLSurface::~GLSurface() { if (GetCurrent() == this) SetCurrent(NULL); } void GLSurface::SetCurrent(GLSurface* surface) { current_surface_.Pointer()->Set(surface); } bool GLSurface::ExtensionsContain(const char* c_extensions, const char* name) { DCHECK(name); if (!c_extensions) return false; std::string extensions(c_extensions); extensions += " "; std::string delimited_name(name); delimited_name += " "; return extensions.find(delimited_name) != std::string::npos; } void GLSurface::OnSetSwapInterval(int interval) { } GLSurfaceAdapter::GLSurfaceAdapter(GLSurface* surface) : surface_(surface) {} bool GLSurfaceAdapter::Initialize() { return surface_->Initialize(); } void GLSurfaceAdapter::Destroy() { surface_->Destroy(); } bool GLSurfaceAdapter::Resize(const gfx::Size& size) { return surface_->Resize(size); } bool GLSurfaceAdapter::Recreate() { return surface_->Recreate(); } bool GLSurfaceAdapter::DeferDraws() { return surface_->DeferDraws(); } bool GLSurfaceAdapter::IsOffscreen() { return surface_->IsOffscreen(); } bool GLSurfaceAdapter::SwapBuffers() { return surface_->SwapBuffers(); } bool GLSurfaceAdapter::SwapBuffersAsync( const SwapCompletionCallback& callback) { return surface_->SwapBuffersAsync(callback); } bool GLSurfaceAdapter::PostSubBuffer(int x, int y, int width, int height) { return surface_->PostSubBuffer(x, y, width, height); } bool GLSurfaceAdapter::PostSubBufferAsync( int x, int y, int width, int height, const SwapCompletionCallback& callback) { return surface_->PostSubBufferAsync(x, y, width, height, callback); } bool GLSurfaceAdapter::SupportsPostSubBuffer() { return surface_->SupportsPostSubBuffer(); } gfx::Size GLSurfaceAdapter::GetSize() { return surface_->GetSize(); } void* GLSurfaceAdapter::GetHandle() { return surface_->GetHandle(); } unsigned int GLSurfaceAdapter::GetBackingFrameBufferObject() { return surface_->GetBackingFrameBufferObject(); } bool GLSurfaceAdapter::OnMakeCurrent(GLContext* context) { return surface_->OnMakeCurrent(context); } bool GLSurfaceAdapter::SetBackbufferAllocation(bool allocated) { return surface_->SetBackbufferAllocation(allocated); } void GLSurfaceAdapter::SetFrontbufferAllocation(bool allocated) { surface_->SetFrontbufferAllocation(allocated); } void* GLSurfaceAdapter::GetShareHandle() { return surface_->GetShareHandle(); } void* GLSurfaceAdapter::GetDisplay() { return surface_->GetDisplay(); } void* GLSurfaceAdapter::GetConfig() { return surface_->GetConfig(); } unsigned GLSurfaceAdapter::GetFormat() { return surface_->GetFormat(); } VSyncProvider* GLSurfaceAdapter::GetVSyncProvider() { return surface_->GetVSyncProvider(); } bool GLSurfaceAdapter::ScheduleOverlayPlane(int z_order, OverlayTransform transform, GLImage* image, const Rect& bounds_rect, const RectF& crop_rect) { return surface_->ScheduleOverlayPlane( z_order, transform, image, bounds_rect, crop_rect); } bool GLSurfaceAdapter::IsSurfaceless() const { return surface_->IsSurfaceless(); } GLSurfaceAdapter::~GLSurfaceAdapter() {} } // namespace gfx