910e62b5创建于 1月15日历史提交
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gl/init/gl_factory.h"

#include <algorithm>
#include <optional>
#include <string>
#include <vector>

#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "ui/gl/gl_features.h"
#include "ui/gl/gl_share_group.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_utils.h"
#include "ui/gl/init/gl_initializer.h"

#if BUILDFLAG(IS_OZONE)
#include "ui/base/ui_base_features.h"
#include "ui/ozone/public/ozone_platform.h"
#endif

namespace gl {
namespace init {

namespace {

GLImplementationParts GetRequestedGLImplementation() {
  const base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
  std::string requested_implementation_gl_name =
      cmd->GetSwitchValueASCII(switches::kUseGL);

  // If --use-angle was specified but --use-gl was not, assume --use-gl=angle
  if (cmd->HasSwitch(switches::kUseANGLE) &&
      !cmd->HasSwitch(switches::kUseGL)) {
    requested_implementation_gl_name = kGLImplementationANGLEName;
  }

  if (requested_implementation_gl_name == kGLImplementationDisabledName) {
    return GLImplementationParts(kGLImplementationDisabled);
  }

  std::vector<GLImplementationParts> allowed_impls =
      GetAllowedGLImplementations();

  // If the passthrough command decoder is enabled, put ANGLE first if allowed
  if (UsePassthroughCommandDecoder(cmd)) {
    std::vector<GLImplementationParts> angle_impls = {};
    std::vector<GLImplementationParts> software_impls = {};
    auto iter = allowed_impls.begin();
    while (iter != allowed_impls.end()) {
      // Filter out disabled software implementations
      if (IsSwiftShaderGLImplementation(*iter) &&
          !features::IsSwiftShaderAllowed(cmd)) {
        iter++;
        continue;
      }
      if (IsWARPGLImplementation(*iter) && !features::IsWARPAllowed(cmd)) {
        iter++;
        continue;
      }

      if (IsSoftwareGLImplementation(*iter)) {
        software_impls.emplace_back(*iter);
        iter = allowed_impls.erase(iter);
      } else if (iter->gl == kGLImplementationEGLANGLE) {
        angle_impls.emplace_back(*iter);
        iter = allowed_impls.erase(iter);
      } else {
        iter++;
      }
    }
    allowed_impls.insert(allowed_impls.begin(), angle_impls.begin(),
                         angle_impls.end());
    // Insert software implementations at the end, after all other hardware
    // implementations.
    allowed_impls.insert(allowed_impls.begin(), software_impls.begin(),
                         software_impls.end());
  }

  if (allowed_impls.empty()) {
    LOG(ERROR) << "List of allowed GL implementations is empty.";
    return GLImplementationParts(kGLImplementationNone);
  }

  std::optional<GLImplementationParts> impl_from_cmdline =
      GetRequestedGLImplementationFromCommandLine(cmd);

  // The default implementation is always the first one in list.
  if (!impl_from_cmdline)
    return allowed_impls[0];

  // Allow software GL if explicitly requested by command line, even if it's not
  // in the allowed_impls list.
  if (IsSoftwareGLImplementation(*impl_from_cmdline))
    return *impl_from_cmdline;

  if (impl_from_cmdline->IsAllowed(allowed_impls))
    return *impl_from_cmdline;

  std::vector<std::string> allowed_impl_strs;
  for (const auto& allowed_impl : allowed_impls) {
    allowed_impl_strs.push_back(allowed_impl.ToString());
  }
  LOG(ERROR) << "Requested GL implementation " << impl_from_cmdline->ToString()
             << " not found in allowed implementations: ["
             << base::JoinString(allowed_impl_strs, ",") << "].";
  return GLImplementationParts(kGLImplementationNone);
}

GLDisplay* InitializeGLOneOffPlatformHelper(bool init_extensions,
                                            gl::GpuPreference gpu_preference) {
  TRACE_EVENT1("gpu,startup", "gl::init::InitializeGLOneOffPlatformHelper",
               "init_extensions", init_extensions);

  const base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
  bool disable_gl_drawing = cmd->HasSwitch(switches::kDisableGLDrawingForTests);

  return InitializeGLOneOffPlatformImplementation(
      disable_gl_drawing, init_extensions, gpu_preference);
}

}  // namespace

GLDisplay* InitializeGLOneOff(gl::GpuPreference gpu_preference) {
  TRACE_EVENT("gpu,startup", "gl::init::InitializeOneOff");

  if (!InitializeStaticGLBindingsOneOff())
    return nullptr;
  if (GetGLImplementation() == kGLImplementationDisabled) {
    return GetDefaultDisplayEGL();
  }

  return InitializeGLOneOffPlatformHelper(true, gpu_preference);
}

GLDisplay* InitializeGLNoExtensionsOneOff(bool init_bindings,
                                          gl::GpuPreference gpu_preference) {
  TRACE_EVENT1("gpu,startup", "gl::init::InitializeNoExtensionsOneOff",
               "init_bindings", init_bindings);
  if (init_bindings) {
    if (!InitializeStaticGLBindingsOneOff())
      return nullptr;
    if (GetGLImplementation() == kGLImplementationDisabled) {
      return GetDefaultDisplayEGL();
    }
  }

  return InitializeGLOneOffPlatformHelper(false, gpu_preference);
}

bool InitializeStaticGLBindingsOneOff() {
  DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
  TRACE_EVENT("gpu,startup", "gl::init::InitializeStaticGLBindingsOneOff");

  GLImplementationParts impl = GetRequestedGLImplementation();
  if (impl.gl == kGLImplementationDisabled) {
    SetGLImplementation(kGLImplementationDisabled);
    return true;
  } else if (impl.gl == kGLImplementationNone) {
    return false;
  }

  return InitializeStaticGLBindingsImplementation(impl);
}

bool InitializeStaticGLBindingsImplementation(GLImplementationParts impl) {
  if (!InitializeStaticGLBindings(impl)) {
    ShutdownGL(nullptr, /*due_to_fallback*/ false);
    return false;
  }
  return true;
}

GLDisplay* InitializeGLOneOffPlatformImplementation(
    bool disable_gl_drawing,
    bool init_extensions,
    gl::GpuPreference gpu_preference) {
  GLDisplay* display = InitializeGLOneOffPlatform(gpu_preference);
  bool initialized = !!display;

  if (!initialized) {
    DVLOG(1) << "Initialization failed. Attempting to initialize default "
                "GLDisplayEGL.";
    RemoveGpuPreferenceEGL(gpu_preference);
    display = InitializeGLOneOffPlatform(gl::GpuPreference::kDefault);
    initialized = !!display;
  }

  if (initialized && init_extensions) {
    initialized = InitializeExtensionSettingsOneOffPlatform(display);
  }

  if (!initialized) {
    ShutdownGL(display, false);
    return nullptr;
  }

  DVLOG(1) << "Using " << GetGLImplementationGLName(GetGLImplementationParts())
           << " GL implementation.";
  SetNullDrawGLBindings(disable_gl_drawing);
  return display;
}

GLDisplay* GetOrInitializeGLOneOffPlatformImplementation(
    bool fallback_to_software_gl,
    bool disable_gl_drawing,
    bool init_extensions,
    gl::GpuPreference gpu_preference) {
  gl::GLDisplay* display = gl::GetDisplay(gpu_preference);
  DCHECK(display);

  if (display->IsInitialized()) {
    return display;
  }

  display = gl::init::InitializeGLOneOffPlatformImplementation(
      /*disable_gl_drawing=*/false, /*init_extensions=*/true,
      /*gpu_preference=*/gpu_preference);

  return display;
}

void ShutdownGL(GLDisplay* display, bool due_to_fallback) {
  ShutdownGLPlatform(display);

  UnloadGLNativeLibraries(due_to_fallback);
  SetGLImplementation(kGLImplementationNone);
}

}  // namespace init
}  // namespace gl