chromium/ui/gl/gl_context.cc

// Copyright 2012 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/gl_context.h"

#include <string>

#include "base/cancelable_callback.h"
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/string_util.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "third_party/abseil-cpp/absl/base/attributes.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_fence.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_switches.h"
#include "ui/gl/gl_version_info.h"
#include "ui/gl/gpu_timing.h"

#if BUILDFLAG(IS_MAC)
#include "base/mac/mac_util.h"
#endif

namespace gl {

namespace {

#if BUILDFLAG(IS_ANDROID)
// Used to represent maximum GLES version for UMA.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class MaximumGLESVersion {
  kGLES2_0 = 0,
  kGLES3_0 = 1,
  kGLES3_1 = 2,
  kGLES3_2 = 3,
  kMaxValue = kGLES3_2
};
#endif

ABSL_CONST_INIT thread_local GLContext* current_context =;
ABSL_CONST_INIT thread_local GLContext* current_real_context =;

}  // namespace

// static
base::subtle::Atomic32 GLContext::total_gl_contexts_ =;
// static
bool GLContext::switchable_gpus_supported_ =;

GLContext::ScopedReleaseCurrent::ScopedReleaseCurrent() :{}

GLContext::ScopedReleaseCurrent::~ScopedReleaseCurrent() {}

void GLContext::ScopedReleaseCurrent::Cancel() {}

GLContextAttribs::GLContextAttribs() = default;
GLContextAttribs::GLContextAttribs(const GLContextAttribs& other) = default;
GLContextAttribs::GLContextAttribs(GLContextAttribs&& other) = default;
GLContextAttribs::~GLContextAttribs() = default;

GLContextAttribs& GLContextAttribs::operator=(const GLContextAttribs& other) =
    default;
GLContextAttribs& GLContextAttribs::operator=(GLContextAttribs&& other) =
    default;

GLContext::GLContext(GLShareGroup* share_group) :{}

GLContext::~GLContext() {}

// static
int32_t GLContext::TotalGLContexts() {}

// static
bool GLContext::SwitchableGPUsSupported() {}

// static
void GLContext::SetSwitchableGPUsSupported() {}

bool GLContext::Initialize(GLSurface* compatible_surface,
                           const GLContextAttribs& attribs) {}

bool GLContext::MakeCurrent(GLSurface* surface) {}

bool GLContext::MakeCurrentDefault() {}

base::WeakPtr<GLContext> GLContext::AsWeakPtr() {}

void GLContext::AddObserver(GLContextObserver* observer) {}

void GLContext::RemoveObserver(GLContextObserver* observer) {}

bool GLContext::CanShareTexturesWithContext(GLContext* other_context) {}

GLApi* GLContext::CreateGLApi(DriverGL* driver) {}

void GLContext::SetSafeToForceGpuSwitch() {}

bool GLContext::ForceGpuSwitchIfNeeded() {}

void GLContext::SetUnbindFboOnMakeCurrent() {}

std::string GLContext::GetGLVersion() {}

std::string GLContext::GetGLRenderer() {}

CurrentGL* GLContext::GetCurrentGL() {}

void GLContext::ReinitializeDynamicBindings() {}

void GLContext::ForceReleaseVirtuallyCurrent() {}

void GLContext::DirtyVirtualContextState() {}

GLDisplayEGL* GLContext::GetGLDisplayEGL() {}

GLContextEGL* GLContext::AsGLContextEGL() {}

#if BUILDFLAG(IS_APPLE)
constexpr uint64_t kInvalidFenceId = 0;

void GLContext::AddMetalSharedEventsForBackpressure(
    std::vector<std::unique_ptr<gpu::BackpressureMetalSharedEvent>> events) {
  for (auto& e : events) {
    next_backpressure_events_.push_back(std::move(e));
  }
}

uint64_t GLContext::BackpressureFenceCreate() {
  TRACE_EVENT0("gpu", "GLContext::BackpressureFenceCreate");

  std::vector<std::unique_ptr<gpu::BackpressureMetalSharedEvent>>
      backpressure_events = std::move(next_backpressure_events_);

  if (gl::GetANGLEImplementation() == gl::ANGLEImplementation::kMetal) {
    // Don't use a GLFence here since we already have Metal shared events
    // corresponding to each GL access and we can avoid any fence overhead.
    backpressure_fences_[++next_backpressure_fence_] = {
        nullptr, std::move(backpressure_events)};
    return next_backpressure_fence_;
  } else if (gl::GLFence::IsSupported()) {
    // This flush will trigger a crash if FlushForDriverCrashWorkaround is not
    // called sufficiently frequently.
    glFlush();
    backpressure_fences_[++next_backpressure_fence_] = {
        GLFence::Create(), std::move(backpressure_events)};
    return next_backpressure_fence_;
  } else {
    glFinish();
    return kInvalidFenceId;
  }
}

void GLContext::BackpressureFenceWait(uint64_t fence_id) {
  TRACE_EVENT0("gpu", "GLContext::BackpressureFenceWait");
  if (fence_id == kInvalidFenceId) {
    return;
  }

  // If a fence is not found, then it has already been waited on.
  auto it = backpressure_fences_.find(fence_id);
  if (it == backpressure_fences_.end()) {
    return;
  }
  auto [fence, events] = std::move(it->second);
  backpressure_fences_.erase(it);

  // Poll for all Metal shared events to be signaled with a 1ms delay.
  bool events_complete = false;
  while (!events_complete) {
    events_complete = true;
    {
      TRACE_EVENT0("gpu", "BackpressureMetalSharedEvent::HasCompleted");
      for (const auto& e : events) {
        if (!e->HasCompleted()) {
          events_complete = false;
          break;
        }
      }
    }
    if (!events_complete) {
      base::PlatformThread::Sleep(base::Milliseconds(1));
    }
  }

  if (fence) {
    fence->ClientWait();
    fence.reset();
  }

  // Waiting on |fence_id| has implicitly waited on all previous fences, so
  // remove them.
  while (!backpressure_fences_.empty() &&
         backpressure_fences_.begin()->first < fence_id) {
    backpressure_fences_.erase(backpressure_fences_.begin());
  }
}

bool GLContext::HasBackpressureFences() const {
  return !backpressure_fences_.empty();
}

void GLContext::DestroyBackpressureFences() {
  backpressure_fences_.clear();
}
#endif

#if BUILDFLAG(IS_MAC)
void GLContext::FlushForDriverCrashWorkaround() {
  // If running on Apple silicon, regardless of the architecture, disable this
  // workaround.  See https://crbug.com/1131312.
  static const bool needs_flush =
      base::mac::GetCPUType() == base::mac::CPUType::kIntel;
  if (!needs_flush || !IsCurrent(nullptr))
    return;
  TRACE_EVENT0("gpu", "GLContext::FlushForDriverCrashWorkaround");
  glFlush();
}
#endif

bool GLContext::HasExtension(const char* name) {}

const GLVersionInfo* GLContext::GetVersionInfo() {}

GLShareGroup* GLContext::share_group() {}

bool GLContext::LosesAllContextsOnContextLost() {}

GLContext* GLContext::GetCurrent() {}

GLContext* GLContext::GetRealCurrent() {}

void GLContext::OnContextWillDestroy() {}

std::unique_ptr<gl::GLVersionInfo> GLContext::GenerateGLVersionInfo() {}

void GLContext::MarkContextLost() {}

void GLContext::SetCurrent(GLSurface* surface) {}

void GLContext::SetDisabledGLExtensions(
    const std::string& disabled_extensions) {}

GLStateRestorer* GLContext::GetGLStateRestorer() {}

void GLContext::SetGLStateRestorer(GLStateRestorer* state_restorer) {}

GLenum GLContext::CheckStickyGraphicsResetStatus() {}

GLenum GLContext::CheckStickyGraphicsResetStatusImpl() {}

void GLContext::InitializeDynamicBindings() {}

bool GLContext::MakeVirtuallyCurrent(
    GLContext* virtual_context, GLSurface* surface) {}

void GLContext::OnReleaseVirtuallyCurrent(GLContext* virtual_context) {}

void GLContext::BindGLApi() {}

GLContextReal::GLContextReal(GLShareGroup* share_group)
    :{}

scoped_refptr<GPUTimingClient> GLContextReal::CreateGPUTimingClient() {}

const gfx::ExtensionSet& GLContextReal::GetExtensions() {}

GLContextReal::~GLContextReal() {}

void GLContextReal::SetCurrent(GLSurface* surface) {}

scoped_refptr<GLContext> InitializeGLContext(scoped_refptr<GLContext> context,
                                             GLSurface* compatible_surface,
                                             const GLContextAttribs& attribs) {}

void GLContextReal::SetExtensionsFromString(std::string extensions) {}

void GLContextReal::ResetExtensions() {}

}  // namespace gl