dhewm3/neo/sys/cpu.cpp
Daniel Gibson 81ba620984 SDL3: Handle r_fillWindowAlphaChan, cleanups and comments
r_fillWindowAlphaChan is a hack to work around an older issue with
Wayland/Mesa, which has been fixed in Mesa 24.1 (and also seems to work
with current NVIDIA drivers). Additionally, in SDL3 the EGL-specific
(and thus mostly only affecting Wayland)
SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY has been replaced with the generic
SDL_PROP_WINDOW_CREATE_TRANSPARENT_BOOLEAN (that could also affect
other platforms), so it's harder to enable this only for Wayland.
I think most people using SDL3 will use a recent Mesa/driver versions,
so I don't enable it by default for SDL3 (SDL2 behaves like before).
However, with `r_fillWindowAlphaChan 1` the hack can be enabled anyway
(r_fillWindowAlphaChan defaults to "-1" which means "let dhewm3 decide
 whether to enable this")
2024-10-29 03:26:20 +01:00

241 lines
5.6 KiB
C++

/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include <float.h>
#ifdef D3_SDL3
#include <SDL3/SDL_cpuinfo.h>
#else // SDL1.2 or SDL2
#include <SDL_cpuinfo.h>
#endif
// MSVC header intrin.h uses strcmp and errors out when not set
#define IDSTR_NO_REDIRECT
#include "sys/platform.h"
#include "framework/Common.h"
#include "sys/sys_public.h"
#ifdef NO_CPUID
#undef NO_CPUID
#endif
#if defined(__GNUC__)
#if !defined(__i386__) && !defined(__x86_64__)
#define NO_CPUID
#endif
#elif defined(_MSC_VER)
#if !defined(_M_IX86)
#define NO_CPUID
#endif
#else
#error unsupported compiler
#endif
#ifdef NO_CPUID
void Sys_FPU_SetDAZ(bool enable) {
}
void Sys_FPU_SetFTZ(bool enable) {
}
#else
#if defined(__GNUC__)
static inline void CPUid(int index, int *a, int *b, int *c, int *d) {
#if __x86_64__
# define REG_b "rbx"
# define REG_S "rsi"
#elif __i386__
# define REG_b "ebx"
# define REG_S "esi"
#endif
*a = *b = *c = *d = 0;
__asm__ volatile
( "mov %%" REG_b ", %%" REG_S "\n\t"
"cpuid\n\t"
"xchg %%" REG_b ", %%" REG_S
: "=a" (*a), "=S" (*b),
"=c" (*c), "=d" (*d)
: "0" (index));
}
#elif defined(_MSC_VER)
#include <intrin.h>
static inline void CPUid(int index, int *a, int *b, int *c, int *d) {
int info[4] = { };
// VS2005 and up
__cpuid(info, index);
*a = info[0];
*b = info[1];
*c = info[2];
*d = info[3];
}
#else
#error unsupported compiler
#endif
#define c_SSE3 (1 << 0)
#define d_FXSAVE (1 << 24)
static inline bool HasDAZ() {
int a, b, c, d;
CPUid(0, &a, &b, &c, &d);
if (a < 1)
return false;
CPUid(1, &a, &b, &c, &d);
return (d & d_FXSAVE) == d_FXSAVE;
}
static inline bool HasSSE3() {
int a, b, c, d;
CPUid(0, &a, &b, &c, &d);
if (a < 1)
return false;
CPUid(1, &a, &b, &c, &d);
return (c & c_SSE3) == c_SSE3;
}
#define MXCSR_DAZ (1 << 6)
#define MXCSR_FTZ (1 << 15)
#ifdef _MSC_VER
#define STREFLOP_FSTCW(cw) do { short tmp; __asm { fstcw tmp }; (cw) = tmp; } while (0)
#define STREFLOP_FLDCW(cw) do { short tmp = (cw); __asm { fclex }; __asm { fldcw tmp }; } while (0)
#define STREFLOP_STMXCSR(cw) do { int tmp; __asm { stmxcsr tmp }; (cw) = tmp; } while (0)
#define STREFLOP_LDMXCSR(cw) do { int tmp = (cw); __asm { ldmxcsr tmp }; } while (0)
#else
#define STREFLOP_FSTCW(cw) do { asm volatile ("fstcw %0" : "=m" (cw) : ); } while (0)
#define STREFLOP_FLDCW(cw) do { asm volatile ("fclex \n fldcw %0" : : "m" (cw)); } while (0)
#define STREFLOP_STMXCSR(cw) do { asm volatile ("stmxcsr %0" : "=m" (cw) : ); } while (0)
#define STREFLOP_LDMXCSR(cw) do { asm volatile ("ldmxcsr %0" : : "m" (cw) ); } while (0)
#endif
static void EnableMXCSRFlag(int flag, bool enable, const char *name) {
int sse_mode;
STREFLOP_STMXCSR(sse_mode);
if (enable && (sse_mode & flag) == flag) {
common->Printf("%s mode is already enabled\n", name);
return;
}
if (!enable && (sse_mode & flag) == 0) {
common->Printf("%s mode is already disabled\n", name);
return;
}
if (enable) {
common->Printf("enabling %s mode\n", name);
sse_mode |= flag;
} else {
common->Printf("disabling %s mode\n", name);
sse_mode &= ~flag;
}
STREFLOP_LDMXCSR(sse_mode);
}
/*
================
Sys_FPU_SetDAZ
================
*/
void Sys_FPU_SetDAZ(bool enable) {
if (!HasDAZ()) {
common->Printf("this CPU doesn't support Denormals-Are-Zero\n");
return;
}
EnableMXCSRFlag(MXCSR_DAZ, enable, "Denormals-Are-Zero");
}
/*
================
Sys_FPU_SetFTZ
================
*/
void Sys_FPU_SetFTZ(bool enable) {
EnableMXCSRFlag(MXCSR_FTZ, enable, "Flush-To-Zero");
}
#endif
/*
================
Sys_GetProcessorId
================
*/
int Sys_GetProcessorId( void ) {
int flags = CPUID_GENERIC;
if (SDL_HasMMX())
flags |= CPUID_MMX;
// SDL3 doesn't support detecting 3DNow, and current CPUs (even from AMD) don't support it either
#ifndef D3_SDL3
if (SDL_Has3DNow())
flags |= CPUID_3DNOW;
#endif
if (SDL_HasSSE())
flags |= CPUID_SSE;
if (SDL_HasSSE2())
flags |= CPUID_SSE2;
#ifndef NO_CPUID
// there is no SDL_HasSSE3() in SDL 1.2
if (HasSSE3())
flags |= CPUID_SSE3;
#endif
if (SDL_HasAltiVec())
flags |= CPUID_ALTIVEC;
return flags;
}
/*
===============
Sys_FPU_SetPrecision
===============
*/
void Sys_FPU_SetPrecision() {
#if defined(_MSC_VER) && defined(_M_IX86)
_controlfp(_PC_64, _MCW_PC);
#endif
}