mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
410 lines
11 KiB
C++
410 lines
11 KiB
C++
// 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 <algorithm>
|
|
#include <vector>
|
|
|
|
#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 <X11/Xlib.h>
|
|
#endif
|
|
|
|
namespace gfx {
|
|
|
|
namespace {
|
|
base::LazyInstance<base::ThreadLocalPointer<GLSurface> >::Leaky
|
|
current_surface_ = LAZY_INSTANCE_INITIALIZER;
|
|
} // namespace
|
|
|
|
// static
|
|
bool GLSurface::InitializeOneOff(GLImplementation impl) {
|
|
DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
|
|
|
|
TRACE_EVENT0("gpu", "GLSurface::InitializeOneOff");
|
|
|
|
std::vector<GLImplementation> 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.
|
|
if (impl == kGLImplementationNone)
|
|
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<GLImplementation> 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(const SurfaceConfiguration requested_configuration)
|
|
: surface_configuration_(requested_configuration) {
|
|
}
|
|
|
|
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)
|
|
: GLSurface(surface->get_surface_configuration()), 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
|