Skip to content

File env.hpp

File List > lib > utilities > env.hpp

Go to the documentation of this file

#pragma once

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>

#if defined(__linux__)
#include <dirent.h>
#include <unistd.h>
#endif

namespace blaze {

// Wrapper around std::getenv that silences MSVC's C4996 "getenv is unsafe" warning.
inline const char* get_env(const char* name) {
#ifdef _WIN32
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
  const char* value = std::getenv(name);
#ifdef _WIN32
#pragma warning(pop)
#endif
  return value;
}

#if defined(__linux__)
inline bool linux_prime_on_demand_configured() {
  FILE* file = std::fopen("/etc/prime-discrete", "r");
  if (!file) {
    return false;
  }
  char mode[64] = {};
  const bool read = std::fgets(mode, static_cast<int>(sizeof(mode)), file) != nullptr;
  std::fclose(file);
  if (!read) {
    return false;
  }
  char* end = mode + std::strlen(mode);
  while (end > mode && (end[-1] == '\n' || end[-1] == '\r' || end[-1] == ' ')) {
    --end;
  }
  *end = '\0';
  return std::strcmp(mode, "on-demand") == 0;
}

inline bool linux_has_multiple_drm_render_nodes() {
  DIR* dir = opendir("/dev/dri");
  if (!dir) {
    return false;
  }
  int render_nodes = 0;
  while (const dirent* entry = readdir(dir)) {
    if (std::strncmp(entry->d_name, "renderD", 7) == 0) {
      ++render_nodes;
      if (render_nodes >= 2) {
        break;
      }
    }
  }
  closedir(dir);
  return render_nodes >= 2;
}

inline bool linux_should_enable_discrete_gpu_offload() {
  if (get_env("BLAZE_USE_IGPU")) {
    return false;
  }
  return get_env("BLAZE_USE_DGPU") || linux_prime_on_demand_configured();
}
#endif

// Route OpenGL rendering to the discrete GPU when the display is on integrated
// graphics (Linux PRIME / NVIDIA render offload). Must run before QApplication.
// Auto-enabled when /etc/prime-discrete is "on-demand" (Ubuntu nvidia-prime).
// Set BLAZE_USE_DGPU=1 to force on other distros; BLAZE_USE_IGPU=1 to opt out.
inline void enable_discrete_gpu_offload() {
#if defined(__linux__)
  if (!linux_should_enable_discrete_gpu_offload()) {
    return;
  }

  if (!get_env("__NV_PRIME_RENDER_OFFLOAD") && access("/dev/nvidia0", F_OK) == 0) {
    setenv("__NV_PRIME_RENDER_OFFLOAD", "1", 0);
    setenv("__GLX_VENDOR_LIBRARY_NAME", "nvidia", 0);
    setenv("__VK_LAYER_NV_optimus", "NVIDIA_only", 0);
    constexpr const char* k_nvidia_egl_vendor = "/usr/share/glvnd/egl_vendor.d/10_nvidia.json";
    if (access(k_nvidia_egl_vendor, F_OK) == 0) {
      setenv("__EGL_VENDOR_LIBRARY_FILENAMES", k_nvidia_egl_vendor, 0);
    }
    std::cerr << "Blaze3D: enabling NVIDIA PRIME render offload for OpenGL\n";
    return;
  }

  if (!get_env("DRI_PRIME") && linux_has_multiple_drm_render_nodes()) {
    setenv("DRI_PRIME", "1", 0);
    std::cerr << "Blaze3D: enabling Mesa PRIME render offload (DRI_PRIME=1) for OpenGL\n";
  }
#endif
}

}  // namespace blaze