chromium/chromecast/starboard/graphics/cast_egl_platform_starboard.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <dlfcn.h>
#include <unistd.h>

#include <cassert>
#include <iostream>

#include "chromecast/public/cast_egl_platform.h"
#include "chromecast/public/cast_egl_platform_shlib.h"
#include "chromecast/public/graphics_types.h"
#include "chromecast/starboard/starboard_buildflags.h"

#if !BUILDFLAG(REMOVE_STARBOARD_HEADERS)
#include <starboard/window.h>

#include "chromecast/starboard/chromecast/starboard_adapter/public/cast_starboard_api_adapter.h"
#endif

namespace chromecast {
namespace {

// TODO(b/333131992): remove [[maybe_unused]] after removing the
// REMOVE_STARBOARD_HEADERS build flag.
[[maybe_unused]] constexpr char kGraphicsLibraryName[] = "libGL_starboard.so";

// Starboard CastEglPlatform implementation.
class CastEglPlatformStarboard : public CastEglPlatform {
 public:
  CastEglPlatformStarboard()
#if !BUILDFLAG(REMOVE_STARBOARD_HEADERS)
      : sb_adapter_(CastStarboardApiAdapter::GetInstance())
#endif
  {
  }

  const int* GetEGLSurfaceProperties(const int* desired) override {
    return desired;
  }

  ~CastEglPlatformStarboard() override {}

  bool InitializeHardware() override {
#if BUILDFLAG(REMOVE_STARBOARD_HEADERS)
    return false;
#else
    if (!sb_adapter_->EnsureInitialized()) {
      return false;
    }
    graphics_lib_ =
        dlopen(kGraphicsLibraryName, RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);
    if (!graphics_lib_) {
      std::cerr << "Failed to dlopen " << kGraphicsLibraryName << std::endl;
      return false;
    }

    get_proc_address_ = reinterpret_cast<GLGetProcAddressProc>(
        dlsym(graphics_lib_, "Sb_eglGetProcAddress"));

    if (!get_proc_address_) {
      std::cerr << "Failed to dlsym Sb_eglGetProcAddress from "
                << kGraphicsLibraryName << std::endl;
      return false;
    }
    return true;
#endif
  }

  void* GetEglLibrary() override { return nullptr; }

  void* GetGles2Library() override { return nullptr; }

  GLGetProcAddressProc GetGLProcAddressProc() override {
    return get_proc_address_;
  }

  NativeDisplayType CreateDisplayType(const Size& size) override {
#if BUILDFLAG(REMOVE_STARBOARD_HEADERS)
    return nullptr;
#else
    // TODO(b/334138792): The need to create a window before getting the display
    // is an implementation detail. Luckily for us, created windows are not
    // visible and GlOzoneEglCast always couples the call to CreateDisplayType
    // and CreateWindow, so there is no downside to creating |window_| early.
    if (!SbWindowIsValid(window_)) {
      SbWindowOptions options{};
      options.name = "cast";
      options.size.width = size.width;
      options.size.height = size.height;
      window_ = sb_adapter_->GetWindow(&options);
    }

    NativeDisplayType ndt = reinterpret_cast<NativeDisplayType>(
        sb_adapter_->GetEglNativeDisplayType());
    return ndt;
#endif
  }

  NativeWindowType CreateWindow(NativeDisplayType display_type,
                                const Size& size) override {
#if BUILDFLAG(REMOVE_STARBOARD_HEADERS)
    return nullptr;
#else
    assert(SbWindowIsValid(window_));
    auto* result =
        static_cast<NativeWindowType>(SbWindowGetPlatformHandle(window_));

    return result;
#endif
  }

 private:
  GLGetProcAddressProc get_proc_address_ = nullptr;
#if !BUILDFLAG(REMOVE_STARBOARD_HEADERS)
  void* graphics_lib_ = nullptr;
  SbWindow window_ = nullptr;
  CastStarboardApiAdapter* sb_adapter_;
#endif
};
}  // namespace

CastEglPlatform* CastEglPlatformShlib::Create(
    const std::vector<std::string>& argv) {
  return new CastEglPlatformStarboard();
}

}  // namespace chromecast