2018-08-05 05:22:15 +00:00
|
|
|
#include "streamutils.h"
|
|
|
|
|
2018-09-04 04:21:37 +00:00
|
|
|
#include <Qt>
|
2024-09-22 01:46:11 +00:00
|
|
|
#include <QDir>
|
2018-09-04 04:21:37 +00:00
|
|
|
|
|
|
|
#ifdef Q_OS_DARWIN
|
|
|
|
#include <ApplicationServices/ApplicationServices.h>
|
|
|
|
#endif
|
|
|
|
|
2024-01-15 19:40:13 +00:00
|
|
|
#ifdef Q_OS_WINDOWS
|
|
|
|
#include <Windows.h>
|
|
|
|
#endif
|
|
|
|
|
2024-09-22 01:46:11 +00:00
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
#include <SDL_syswm.h>
|
|
|
|
#endif
|
|
|
|
|
2024-01-15 20:16:56 +00:00
|
|
|
#ifdef Q_OS_LINUX
|
|
|
|
#include <sys/auxv.h>
|
2024-01-15 23:36:57 +00:00
|
|
|
|
2024-01-23 08:28:28 +00:00
|
|
|
#if defined(Q_PROCESSOR_ARM)
|
|
|
|
|
2024-01-15 23:36:57 +00:00
|
|
|
#ifndef HWCAP2_AES
|
|
|
|
#define HWCAP2_AES (1 << 0)
|
|
|
|
#endif
|
2024-01-23 08:28:28 +00:00
|
|
|
|
|
|
|
#elif defined(Q_PROCESSOR_RISCV)
|
|
|
|
|
|
|
|
#if __has_include(<sys/hwprobe.h>)
|
|
|
|
#include <sys/hwprobe.h>
|
|
|
|
#else
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#if __has_include(<asm/hwprobe.h>)
|
|
|
|
#include <asm/hwprobe.h>
|
|
|
|
#include <sys/syscall.h>
|
|
|
|
#else
|
|
|
|
#define __NR_riscv_hwprobe 258
|
|
|
|
struct riscv_hwprobe {
|
|
|
|
int64_t key;
|
|
|
|
uint64_t value;
|
|
|
|
};
|
|
|
|
#define RISCV_HWPROBE_KEY_IMA_EXT_0 4
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// RISC-V Scalar AES [E]ncryption and [D]ecryption
|
|
|
|
#ifndef RISCV_HWPROBE_EXT_ZKND
|
|
|
|
#define RISCV_HWPROBE_EXT_ZKND (1 << 11)
|
|
|
|
#define RISCV_HWPROBE_EXT_ZKNE (1 << 12)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// RISC-V Vector AES
|
|
|
|
#ifndef RISCV_HWPROBE_EXT_ZVKNED
|
|
|
|
#define RISCV_HWPROBE_EXT_ZVKNED (1 << 21)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int __riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
|
|
|
|
size_t cpu_count, unsigned long *cpus,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
return syscall(__NR_riscv_hwprobe, pairs, pair_count, cpu_count, cpus, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
#endif
|
2024-01-15 20:16:56 +00:00
|
|
|
#endif
|
|
|
|
|
2020-09-05 21:06:56 +00:00
|
|
|
Uint32 StreamUtils::getPlatformWindowFlags()
|
|
|
|
{
|
2023-12-13 05:54:23 +00:00
|
|
|
#if defined(Q_OS_DARWIN)
|
2020-09-05 21:06:56 +00:00
|
|
|
return SDL_WINDOW_METAL;
|
2023-12-13 05:54:23 +00:00
|
|
|
#elif defined(HAVE_LIBPLACEBO_VULKAN)
|
|
|
|
// We'll fall back to GL if Vulkan fails
|
|
|
|
return SDL_WINDOW_VULKAN;
|
2020-09-05 21:06:56 +00:00
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-08-05 05:22:15 +00:00
|
|
|
void StreamUtils::scaleSourceToDestinationSurface(SDL_Rect* src, SDL_Rect* dst)
|
|
|
|
{
|
2022-10-15 18:12:18 +00:00
|
|
|
int dstH = SDL_ceilf((float)dst->w * src->h / src->w);
|
|
|
|
int dstW = SDL_ceilf((float)dst->h * src->w / src->h);
|
2018-08-05 05:22:15 +00:00
|
|
|
|
|
|
|
if (dstH > dst->h) {
|
2020-02-25 02:01:30 +00:00
|
|
|
dst->x += (dst->w - dstW) / 2;
|
2018-08-05 05:22:15 +00:00
|
|
|
dst->w = dstW;
|
|
|
|
}
|
|
|
|
else {
|
2020-02-25 02:01:30 +00:00
|
|
|
dst->y += (dst->h - dstH) / 2;
|
2018-08-05 05:22:15 +00:00
|
|
|
dst->h = dstH;
|
|
|
|
}
|
|
|
|
}
|
2018-09-04 04:21:37 +00:00
|
|
|
|
2022-04-05 05:50:04 +00:00
|
|
|
void StreamUtils::screenSpaceToNormalizedDeviceCoords(SDL_FRect* rect, int viewportWidth, int viewportHeight)
|
|
|
|
{
|
|
|
|
rect->x = (rect->x / (viewportWidth / 2.0f)) - 1.0f;
|
|
|
|
rect->y = (rect->y / (viewportHeight / 2.0f)) - 1.0f;
|
|
|
|
rect->w = rect->w / (viewportWidth / 2.0f);
|
|
|
|
rect->h = rect->h / (viewportHeight / 2.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
void StreamUtils::screenSpaceToNormalizedDeviceCoords(SDL_Rect* src, SDL_FRect* dst, int viewportWidth, int viewportHeight)
|
|
|
|
{
|
|
|
|
dst->x = ((float)src->x / (viewportWidth / 2.0f)) - 1.0f;
|
|
|
|
dst->y = ((float)src->y / (viewportHeight / 2.0f)) - 1.0f;
|
|
|
|
dst->w = (float)src->w / (viewportWidth / 2.0f);
|
|
|
|
dst->h = (float)src->h / (viewportHeight / 2.0f);
|
|
|
|
}
|
|
|
|
|
2018-09-08 22:09:46 +00:00
|
|
|
int StreamUtils::getDisplayRefreshRate(SDL_Window* window)
|
|
|
|
{
|
|
|
|
int displayIndex = SDL_GetWindowDisplayIndex(window);
|
|
|
|
if (displayIndex < 0) {
|
|
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
|
|
"Failed to get current display: %s",
|
|
|
|
SDL_GetError());
|
|
|
|
|
|
|
|
// Assume display 0 if it fails
|
|
|
|
displayIndex = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_DisplayMode mode;
|
|
|
|
if ((SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN) {
|
|
|
|
// Use the window display mode for full-screen exclusive mode
|
|
|
|
if (SDL_GetWindowDisplayMode(window, &mode) != 0) {
|
|
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
|
|
"SDL_GetWindowDisplayMode() failed: %s",
|
|
|
|
SDL_GetError());
|
|
|
|
|
|
|
|
// Assume 60 Hz
|
|
|
|
return 60;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Use the current display mode for windowed and borderless
|
|
|
|
if (SDL_GetCurrentDisplayMode(displayIndex, &mode) != 0) {
|
|
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
|
|
"SDL_GetCurrentDisplayMode() failed: %s",
|
|
|
|
SDL_GetError());
|
|
|
|
|
|
|
|
// Assume 60 Hz
|
|
|
|
return 60;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// May be zero if undefined
|
|
|
|
if (mode.refresh_rate == 0) {
|
|
|
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
|
|
"Refresh rate unknown; assuming 60 Hz");
|
|
|
|
mode.refresh_rate = 60;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mode.refresh_rate;
|
|
|
|
}
|
|
|
|
|
2024-01-15 19:40:13 +00:00
|
|
|
bool StreamUtils::hasFastAes()
|
|
|
|
{
|
|
|
|
#ifndef __has_builtin
|
|
|
|
#define __has_builtin(x) 0
|
|
|
|
#endif
|
|
|
|
|
2024-02-17 19:28:32 +00:00
|
|
|
#if (__has_builtin(__builtin_cpu_supports) || (defined(__GNUC__) && __GNUC__ >= 6)) && defined(Q_PROCESSOR_X86)
|
2024-01-15 19:40:13 +00:00
|
|
|
return __builtin_cpu_supports("aes");
|
|
|
|
#elif defined(__BUILTIN_CPU_SUPPORTS__) && defined(Q_PROCESSOR_POWER)
|
|
|
|
return __builtin_cpu_supports("vcrypto");
|
|
|
|
#elif defined(Q_OS_WINDOWS) && defined(Q_PROCESSOR_ARM)
|
|
|
|
return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
|
|
|
|
#elif defined(_MSC_VER) && defined(Q_PROCESSOR_X86)
|
|
|
|
int regs[4];
|
|
|
|
__cpuid(regs, 1);
|
|
|
|
return regs[2] & (1 << 25); // AES-NI
|
|
|
|
#elif defined(Q_OS_DARWIN)
|
|
|
|
// Everything that runs Catalina and later has AES-NI or ARMv8 crypto instructions
|
|
|
|
return true;
|
2024-01-15 20:16:56 +00:00
|
|
|
#elif defined(Q_OS_LINUX) && defined(Q_PROCESSOR_ARM) && QT_POINTER_SIZE == 4
|
|
|
|
return getauxval(AT_HWCAP2) & HWCAP2_AES;
|
|
|
|
#elif defined(Q_OS_LINUX) && defined(Q_PROCESSOR_ARM) && QT_POINTER_SIZE == 8
|
|
|
|
return getauxval(AT_HWCAP) & HWCAP_AES;
|
2024-01-15 23:36:57 +00:00
|
|
|
#elif defined(Q_PROCESSOR_RISCV)
|
2024-01-23 08:28:28 +00:00
|
|
|
riscv_hwprobe pairs[1] = {
|
|
|
|
{ RISCV_HWPROBE_KEY_IMA_EXT_0, 0 },
|
|
|
|
};
|
|
|
|
|
|
|
|
// If this syscall is not implemented, we'll get -ENOSYS
|
|
|
|
// and the value field will remain zero.
|
|
|
|
__riscv_hwprobe(pairs, SDL_arraysize(pairs), 0, nullptr, 0);
|
|
|
|
|
|
|
|
return (pairs[0].value & (RISCV_HWPROBE_EXT_ZKNE | RISCV_HWPROBE_EXT_ZKND)) ==
|
|
|
|
(RISCV_HWPROBE_EXT_ZKNE | RISCV_HWPROBE_EXT_ZKND) ||
|
|
|
|
(pairs[0].value & RISCV_HWPROBE_EXT_ZVKNED);
|
2024-01-15 20:16:56 +00:00
|
|
|
#elif QT_POINTER_SIZE == 4
|
|
|
|
#warning Unknown 32-bit platform. Assuming AES is slow on this CPU.
|
|
|
|
return false;
|
2024-01-15 19:40:13 +00:00
|
|
|
#else
|
2024-01-15 20:16:56 +00:00
|
|
|
#warning Unknown 64-bit platform. Assuming AES is fast on this CPU.
|
2024-01-15 19:40:13 +00:00
|
|
|
return true;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2024-05-11 23:24:40 +00:00
|
|
|
bool StreamUtils::getNativeDesktopMode(int displayIndex, SDL_DisplayMode* mode, SDL_Rect* safeArea)
|
2018-09-04 04:21:37 +00:00
|
|
|
{
|
|
|
|
#ifdef Q_OS_DARWIN
|
|
|
|
#define MAX_DISPLAYS 16
|
|
|
|
CGDirectDisplayID displayIds[MAX_DISPLAYS];
|
|
|
|
uint32_t displayCount = 0;
|
|
|
|
CGGetActiveDisplayList(MAX_DISPLAYS, displayIds, &displayCount);
|
|
|
|
if (displayIndex >= displayCount) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-05-09 23:51:18 +00:00
|
|
|
SDL_zerop(mode);
|
2018-09-04 04:21:37 +00:00
|
|
|
|
|
|
|
// Retina displays have non-native resolutions both below and above (!) their
|
|
|
|
// native resolution, so it's impossible for us to figure out what's actually
|
|
|
|
// native on macOS using the SDL API alone. We'll talk to CoreGraphics to
|
|
|
|
// find the correct resolution and match it in our SDL list.
|
2020-05-09 23:51:18 +00:00
|
|
|
CFArrayRef modeList = CGDisplayCopyAllDisplayModes(displayIds[displayIndex], nullptr);
|
2018-09-04 04:21:37 +00:00
|
|
|
CFIndex count = CFArrayGetCount(modeList);
|
|
|
|
for (CFIndex i = 0; i < count; i++) {
|
|
|
|
auto cgMode = (CGDisplayModeRef)(CFArrayGetValueAtIndex(modeList, i));
|
2020-05-09 23:51:18 +00:00
|
|
|
if ((CGDisplayModeGetIOFlags(cgMode) & kDisplayModeNativeFlag) != 0) {
|
|
|
|
mode->w = static_cast<int>(CGDisplayModeGetWidth(cgMode));
|
|
|
|
mode->h = static_cast<int>(CGDisplayModeGetHeight(cgMode));
|
2018-09-04 04:21:37 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2024-05-11 23:24:40 +00:00
|
|
|
|
|
|
|
safeArea->x = 0;
|
|
|
|
safeArea->y = 0;
|
|
|
|
safeArea->w = mode->w;
|
|
|
|
safeArea->h = mode->h;
|
|
|
|
|
|
|
|
#if TARGET_CPU_ARM64
|
|
|
|
// Now that we found the native full-screen mode, let's look for one that matches along
|
|
|
|
// the width but not the height and we'll assume that's the safe area full-screen mode.
|
|
|
|
//
|
|
|
|
// There doesn't appear to be a CG API or flag that will tell us that a given mode
|
|
|
|
// is a "safe area" mode, so we have to use our own (brittle) heuristics. :(
|
|
|
|
//
|
|
|
|
// To avoid potential false positives, let's avoid checking for external displays, since
|
|
|
|
// we might have scenarios like a 1920x1200 display with an alternate 1920x1080 mode
|
|
|
|
// which would falsely trigger our notch detection here.
|
|
|
|
if (CGDisplayIsBuiltin(displayIds[displayIndex])) {
|
|
|
|
for (CFIndex i = 0; i < count; i++) {
|
|
|
|
auto cgMode = (CGDisplayModeRef)(CFArrayGetValueAtIndex(modeList, i));
|
|
|
|
auto cgModeWidth = static_cast<int>(CGDisplayModeGetWidth(cgMode));
|
|
|
|
auto cgModeHeight = static_cast<int>(CGDisplayModeGetHeight(cgMode));
|
|
|
|
|
|
|
|
// If the modes differ by more than 100, we'll assume it's not a notch mode
|
|
|
|
if (mode->w == cgModeWidth && mode->h != cgModeHeight && mode->h <= cgModeHeight + 100) {
|
|
|
|
safeArea->w = cgModeWidth;
|
|
|
|
safeArea->h = cgModeHeight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-05-09 23:34:48 +00:00
|
|
|
CFRelease(modeList);
|
2020-05-09 23:51:18 +00:00
|
|
|
|
2024-05-12 00:54:52 +00:00
|
|
|
// Special case for probing for notched displays prior to video subsystem initialization
|
|
|
|
// in Session::initialize() for Darwin only!
|
|
|
|
if (SDL_WasInit(SDL_INIT_VIDEO)) {
|
|
|
|
// Now find the SDL mode that matches the CG native mode
|
|
|
|
for (int i = 0; i < SDL_GetNumDisplayModes(displayIndex); i++) {
|
|
|
|
SDL_DisplayMode thisMode;
|
|
|
|
if (SDL_GetDisplayMode(displayIndex, i, &thisMode) == 0) {
|
|
|
|
if (thisMode.w == mode->w && thisMode.h == mode->h &&
|
2020-05-09 23:51:18 +00:00
|
|
|
thisMode.refresh_rate >= mode->refresh_rate) {
|
2024-05-12 00:54:52 +00:00
|
|
|
*mode = thisMode;
|
|
|
|
break;
|
|
|
|
}
|
2020-05-09 23:51:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-09-04 04:21:37 +00:00
|
|
|
#else
|
2024-05-12 00:54:52 +00:00
|
|
|
SDL_assert(SDL_WasInit(SDL_INIT_VIDEO));
|
|
|
|
|
|
|
|
if (displayIndex >= SDL_GetNumVideoDisplays()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-08-16 05:25:49 +00:00
|
|
|
// We need to get the true display resolution without DPI scaling (since we use High DPI).
|
|
|
|
// Windows returns the real display resolution here, even if DPI scaling is enabled.
|
|
|
|
// macOS and Wayland report a resolution that includes the DPI scaling factor. Picking
|
|
|
|
// the first mode on Wayland will get the native resolution without the scaling factor
|
|
|
|
// (and macOS is handled in the #ifdef above).
|
|
|
|
if (!strcmp(SDL_GetCurrentVideoDriver(), "wayland")) {
|
|
|
|
if (SDL_GetDisplayMode(displayIndex, 0, mode) != 0) {
|
|
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
|
|
"SDL_GetDisplayMode() failed: %s",
|
|
|
|
SDL_GetError());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (SDL_GetDesktopDisplayMode(displayIndex, mode) != 0) {
|
|
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
|
|
"SDL_GetDesktopDisplayMode() failed: %s",
|
|
|
|
SDL_GetError());
|
|
|
|
return false;
|
|
|
|
}
|
2018-09-04 04:21:37 +00:00
|
|
|
}
|
2024-05-11 23:24:40 +00:00
|
|
|
|
|
|
|
safeArea->x = 0;
|
|
|
|
safeArea->y = 0;
|
|
|
|
safeArea->w = mode->w;
|
|
|
|
safeArea->h = mode->h;
|
2018-09-04 04:21:37 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2024-05-11 23:24:40 +00:00
|
|
|
|
2024-09-22 01:46:11 +00:00
|
|
|
int StreamUtils::getDrmFdForWindow(SDL_Window* window, bool* mustClose)
|
|
|
|
{
|
|
|
|
*mustClose = false;
|
|
|
|
|
|
|
|
#if defined(SDL_VIDEO_DRIVER_KMSDRM) && SDL_VERSION_ATLEAST(2, 0, 15)
|
|
|
|
SDL_SysWMinfo info;
|
|
|
|
SDL_VERSION(&info.version);
|
|
|
|
if (!SDL_GetWindowWMInfo(window, &info)) {
|
|
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
|
|
"SDL_GetWindowWMInfo() failed: %s",
|
|
|
|
SDL_GetError());
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info.subsystem == SDL_SYSWM_KMSDRM) {
|
|
|
|
// If SDL has an FD, share that
|
|
|
|
if (info.info.kmsdrm.drm_fd >= 0) {
|
|
|
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
|
|
"Sharing DRM FD with SDL");
|
|
|
|
return info.info.kmsdrm.drm_fd;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
char path[128];
|
|
|
|
snprintf(path, sizeof(path), "/dev/dri/card%u", info.info.kmsdrm.dev_index);
|
|
|
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
|
|
"Opening DRM FD from SDL by path: %s",
|
|
|
|
path);
|
|
|
|
int fd = open(path, O_RDWR | O_CLOEXEC);
|
|
|
|
if (fd >= 0) {
|
|
|
|
*mustClose = true;
|
|
|
|
}
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
}
|
2024-09-28 05:08:35 +00:00
|
|
|
#else
|
|
|
|
Q_UNUSED(window);
|
2024-09-22 01:46:11 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int StreamUtils::getDrmFd(bool preferRenderNode)
|
|
|
|
{
|
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
const char* userDevice = SDL_getenv("DRM_DEV");
|
|
|
|
if (userDevice != nullptr) {
|
|
|
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
|
|
"Opening user-specified DRM device: %s",
|
|
|
|
userDevice);
|
|
|
|
|
|
|
|
return open(userDevice, O_RDWR | O_CLOEXEC);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
QDir driDir("/dev/dri");
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
// We have to explicitly ask for devices to be returned
|
|
|
|
driDir.setFilter(QDir::Files | QDir::System);
|
|
|
|
|
|
|
|
if (preferRenderNode) {
|
|
|
|
// Try a render node first since we aren't using DRM for output in this codepath
|
|
|
|
for (QFileInfo& node : driDir.entryInfoList(QStringList("renderD*"))) {
|
|
|
|
QByteArray absolutePath = node.absoluteFilePath().toUtf8();
|
|
|
|
fd = open(absolutePath.constData(), O_RDWR | O_CLOEXEC);
|
|
|
|
if (fd >= 0) {
|
|
|
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
|
|
"Opened DRM render node: %s",
|
|
|
|
absolutePath.constData());
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If that fails, try to use a primary node and hope for the best
|
|
|
|
for (QFileInfo& node : driDir.entryInfoList(QStringList("card*"))) {
|
|
|
|
QByteArray absolutePath = node.absoluteFilePath().toUtf8();
|
|
|
|
fd = open(absolutePath.constData(), O_RDWR | O_CLOEXEC);
|
|
|
|
if (fd >= 0) {
|
|
|
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
|
|
"Opened DRM primary node: %s",
|
|
|
|
absolutePath.constData());
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-09-28 05:08:35 +00:00
|
|
|
#else
|
|
|
|
Q_UNUSED(preferRenderNode);
|
2024-09-22 01:46:11 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|