Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
efe70fe
macOS: add Platform/Mac files and Apple Silicon CMake support
iamaperson000 May 30, 2026
49c6d69
Fix macOS CMake: SDL2, libunwind, GLAD, OpenAL EFX, linker warnings
MarkKropf Feb 27, 2026
b22cb25
Fix DevIL include path and add missing headless GL stubs
MarkKropf Feb 27, 2026
4199e07
Fix macOS ARM64 build against upstream master
MarkKropf Apr 12, 2026
16622a9
Fix INLINE macro collision between smmalloc and simdjson
MarkKropf Feb 27, 2026
43ae6c9
Fix vendored library compilation on macOS/Clang
MarkKropf Feb 27, 2026
cc3cad9
Fix macOS Clang C++ compatibility issues
MarkKropf Feb 27, 2026
1e75080
Rendering: guard CTextureAtlas::GetTexID against null atlasTex
iamaperson000 May 28, 2026
13a0c60
Window: persist logical (point) size, not the backing-pixel size
iamaperson000 May 29, 2026
17c55de
GL: skip legacy ARB-extension name check on core-profile contexts
iamaperson000 May 30, 2026
28c2a93
macOS: parameterize Mesa libEGL via SPRING_MAC_LIBEGL
iamaperson000 May 28, 2026
08d2b01
macOS: add EGL init diagnostics
iamaperson000 May 28, 2026
6e2ccc1
macOS: run engine on Mesa surfaceless EGL + Zink + KosmicKrisp
iamaperson000 May 30, 2026
52f065e
macOS: manual Metal present path (pbuffer -> CAMetalLayer)
iamaperson000 May 28, 2026
f549beb
macOS: present real frames via SwapBuffers
iamaperson000 May 28, 2026
1dc0591
macOS: IOSurface zero-copy present (glReadPixels -> MTLTexture)
iamaperson000 May 29, 2026
6a60935
GlobalRendering: viewport must match the FBO, not the drawable
iamaperson000 May 30, 2026
4f0dbc4
macOS/Zink: prefer GL compatibility-profile context
iamaperson000 May 28, 2026
a98ba7a
Rendering: env-gated headless frame capture (SPRING_FRAME_CAPTURE)
iamaperson000 May 28, 2026
4eb4f56
Rendering: async PBO readback + downsample / timing knobs
iamaperson000 May 30, 2026
e46af54
macOS: enable BAR Lua loading screen (CLuaIntro) by default
iamaperson000 May 30, 2026
3e2f933
LuaShaders: gate geometry-shader strip to macOS only
iamaperson000 May 30, 2026
5b60718
macOS: scale SDL mouse coords from logical points to backing pixels
iamaperson000 May 30, 2026
a255306
CMake: restore Lua/LuaLibs.cpp in dedicated and unitsync sources
iamaperson000 May 31, 2026
44e9078
LuaShaders: gate GS-strip diagnostics inside __APPLE__ block
iamaperson000 May 31, 2026
d39f04e
CMake: scope macOS-specific tweaks so Linux builds are unaffected
iamaperson000 May 31, 2026
5340742
Sound: move vendored OpenAL EFX headers under include/Mac/AL/
iamaperson000 May 31, 2026
6127c9c
macOS: detect P/E core split and hint QOS for sim workers
iamaperson000 May 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions AI/Wrappers/CUtils/Util.c
Original file line number Diff line number Diff line change
Expand Up @@ -487,11 +487,7 @@ static void util_initFileSelector(const char* suffix) {
fileSelectorSuffix = suffix;
}

#if defined(__APPLE__)
static int util_fileSelector(struct dirent* fileDesc) {
#else
static int util_fileSelector(const struct dirent* fileDesc) {
#endif
return util_endsWith(fileDesc->d_name, fileSelectorSuffix);
}

Expand Down
51 changes: 51 additions & 0 deletions include/Mac/AL/alext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* OpenAL extensions header — vendored for macOS compatibility.
*
* Apple's OpenAL.framework does not include alext.h.
* These constants and typedefs are from OpenAL-Soft's alext.h
* for the ALC_SOFT_loopback extension used by the sound system.
*
* Functions are loaded at runtime via alcGetProcAddress().
*/

#ifndef AL_ALEXT_H
#define AL_ALEXT_H

#include <al.h>
#include <alc.h>

#ifdef __cplusplus
extern "C" {
#endif

/* ALC_SOFT_loopback */
#define ALC_SOFT_loopback 1
#define ALC_FORMAT_CHANNELS_SOFT 0x1990
#define ALC_FORMAT_TYPE_SOFT 0x1991

/* Sample types */
#define ALC_BYTE_SOFT 0x1400
#define ALC_UNSIGNED_BYTE_SOFT 0x1401
#define ALC_SHORT_SOFT 0x1402
#define ALC_UNSIGNED_SHORT_SOFT 0x1403
#define ALC_INT_SOFT 0x1404
#define ALC_UNSIGNED_INT_SOFT 0x1405
#define ALC_FLOAT_SOFT 0x1406

/* Channel configurations */
#define ALC_MONO_SOFT 0x1500
#define ALC_STEREO_SOFT 0x1501
#define ALC_QUAD_SOFT 0x1503
#define ALC_5POINT1_SOFT 0x1504
#define ALC_6POINT1_SOFT 0x1505
#define ALC_7POINT1_SOFT 0x1506

/* Loopback function pointer types */
typedef ALCdevice* (ALC_APIENTRY *LPALCLOOPBACKOPENDEVICESOFT)(const ALCchar*);
typedef ALCboolean (ALC_APIENTRY *LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice*, ALCsizei, ALCenum, ALCenum);
typedef void (ALC_APIENTRY *LPALCRENDERSAMPLESSOFT)(ALCdevice*, ALCvoid*, ALCsizei);

#ifdef __cplusplus
}
#endif

#endif /* AL_ALEXT_H */
149 changes: 149 additions & 0 deletions include/Mac/AL/efx.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/* OpenAL EFX extension header — vendored for macOS compatibility.
*
* Apple's OpenAL.framework does not include EFX headers.
* These constants and typedefs are from the OpenAL 1.1 EFX specification
* (originally distributed with OpenAL-Soft).
*
* Functions are loaded at runtime via alGetProcAddress() in EFXfuncs.cpp,
* so only compile-time constants and typedefs are needed here.
*/

#ifndef AL_EFX_H
#define AL_EFX_H

#include <al.h>
#include <alc.h>

#ifdef __cplusplus
extern "C" {
#endif

/* Effect types */
#define AL_EFFECT_TYPE 0x8001
#define AL_EFFECT_NULL 0x0000
#define AL_EFFECT_REVERB 0x0001
#define AL_EFFECT_CHORUS 0x0002
#define AL_EFFECT_DISTORTION 0x0003
#define AL_EFFECT_ECHO 0x0004
#define AL_EFFECT_FLANGER 0x0005
#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006
#define AL_EFFECT_VOCAL_MORPHER 0x0007
#define AL_EFFECT_PITCH_SHIFTER 0x0008
#define AL_EFFECT_RING_MODULATOR 0x0009
#define AL_EFFECT_AUTOWAH 0x000A
#define AL_EFFECT_COMPRESSOR 0x000B
#define AL_EFFECT_EQUALIZER 0x000C
#define AL_EFFECT_EAXREVERB 0x8000

/* EAX Reverb effect parameters */
#define AL_EAXREVERB_DENSITY 0x0001
#define AL_EAXREVERB_DIFFUSION 0x0002
#define AL_EAXREVERB_GAIN 0x0003
#define AL_EAXREVERB_GAINHF 0x0004
#define AL_EAXREVERB_GAINLF 0x0005
#define AL_EAXREVERB_DECAY_TIME 0x0006
#define AL_EAXREVERB_DECAY_HFRATIO 0x0007
#define AL_EAXREVERB_DECAY_LFRATIO 0x0008
#define AL_EAXREVERB_REFLECTIONS_GAIN 0x0009
#define AL_EAXREVERB_REFLECTIONS_DELAY 0x000A
#define AL_EAXREVERB_REFLECTIONS_PAN 0x000B
#define AL_EAXREVERB_LATE_REVERB_GAIN 0x000C
#define AL_EAXREVERB_LATE_REVERB_DELAY 0x000D
#define AL_EAXREVERB_LATE_REVERB_PAN 0x000E
#define AL_EAXREVERB_ECHO_TIME 0x000F
#define AL_EAXREVERB_ECHO_DEPTH 0x0010
#define AL_EAXREVERB_MODULATION_TIME 0x0011
#define AL_EAXREVERB_MODULATION_DEPTH 0x0012
#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF 0x0013
#define AL_EAXREVERB_HFREFERENCE 0x0014
#define AL_EAXREVERB_LFREFERENCE 0x0015
#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016
#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017

/* Filter types */
#define AL_FILTER_TYPE 0x8001
#define AL_FILTER_NULL 0x0000
#define AL_FILTER_LOWPASS 0x0001
#define AL_FILTER_HIGHPASS 0x0002
#define AL_FILTER_BANDPASS 0x0003

/* Lowpass filter parameters */
#define AL_LOWPASS_GAIN 0x0001
#define AL_LOWPASS_GAINHF 0x0002

/* Highpass filter parameters */
#define AL_HIGHPASS_GAIN 0x0001
#define AL_HIGHPASS_GAINLF 0x0002

/* Bandpass filter parameters */
#define AL_BANDPASS_GAIN 0x0001
#define AL_BANDPASS_GAINLF 0x0002
#define AL_BANDPASS_GAINHF 0x0003

/* Auxiliary effect slot properties */
#define AL_EFFECTSLOT_EFFECT 0x0001
#define AL_EFFECTSLOT_GAIN 0x0002
#define AL_EFFECTSLOT_AUXILIARY_SEND_AUTO 0x0003
#define AL_EFFECTSLOT_NULL 0x0000

/* Context attribute for max auxiliary sends */
#define ALC_MAX_AUXILIARY_SENDS 0x20003

/* Air absorption factor range */
#define AL_MIN_AIR_ABSORPTION_FACTOR 0.0f
#define AL_MAX_AIR_ABSORPTION_FACTOR 10.0f

/* Source properties for auxiliary send filter */
#define AL_DIRECT_FILTER 0x20005
#define AL_AUXILIARY_SEND_FILTER 0x20006
#define AL_AIR_ABSORPTION_FACTOR 0x20007
#define AL_DIRECT_FILTER_GAINHF_AUTO 0x2000B
#define AL_AUXILIARY_SEND_FILTER_GAIN_AUTO 0x2000C
#define AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO 0x2000D

/* EFX function pointer types — loaded at runtime via alGetProcAddress() */

/* Effect functions */
typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*);
typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, const ALuint*);
typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint);
typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint);
typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, const ALint*);
typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat);
typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, const ALfloat*);
typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*);
typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*);

/* Filter functions */
typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*);
typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, const ALuint*);
typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint);
typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint);
typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, const ALint*);
typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat);
typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, const ALfloat*);
typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*);
typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*);

/* Auxiliary effect slot functions */
typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*);
typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, const ALuint*);
typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint);
typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint);
typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, const ALint*);
typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat);
typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, const ALfloat*);
typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*);
typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*);

#ifdef __cplusplus
}
#endif

#endif /* AL_EFX_H */
6 changes: 5 additions & 1 deletion rts/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ endif()

### give error when not found
find_package_static(DevIL REQUIRED)
# DevIL's CMake module sets IL_INCLUDE_DIR to the directory containing il.h (e.g. /include/IL)
# but code uses #include <IL/il.h>, so we need the parent directory
get_filename_component(_IL_PARENT_DIR "${IL_INCLUDE_DIR}" DIRECTORY)
include_directories(${_IL_PARENT_DIR})

### Assemble common include dirs
include_directories(BEFORE lib)
Expand Down Expand Up @@ -106,7 +110,7 @@ if (USE_MIMALLOC)
endif (USE_MIMALLOC)


if(UNIX AND NOT (CMAKE_SYSTEM_NAME MATCHES "OpenBSD"))
if(UNIX AND NOT APPLE AND NOT (CMAKE_SYSTEM_NAME MATCHES "OpenBSD"))
find_package_static(Libunwind 1.4.0 REQUIRED)
prefer_static_libs()
find_library(LZMA_LIBRARY lzma)
Expand Down
14 changes: 14 additions & 0 deletions rts/Game/LoadScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,21 @@ bool CLoadScreen::Init()
// the global font), the latter will cause problems in GL4
{
auto lock = CLoadLock::GetUniqueLock();
#if defined(__APPLE__)
// The Lua intro was disabled on macOS as an EGL-path workaround (it uses
// the global font / gl.*Text which broke under the old core-profile
// shaders). With the compatibility-profile context + fixed font/render-
// buffer shaders it renders correctly (full BAR splash + progress), so
// it is enabled by default. Set SPRING_MAC_DISABLE_LUAINTRO=1 to skip it
// (falls back to a black load screen) if it ever misbehaves.
if (getenv("SPRING_MAC_DISABLE_LUAINTRO") != nullptr) {
LOG("[LoadScreen::%s] skipping CLuaIntro (SPRING_MAC_DISABLE_LUAINTRO)", __func__);
} else {
CLuaIntro::LoadFreeHandler();
}
#else
CLuaIntro::LoadFreeHandler();
#endif
}

if (mtLoading)
Expand Down
21 changes: 21 additions & 0 deletions rts/Lua/LuaShaders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,27 @@ int LuaShaders::CreateShader(lua_State* L)
if (!ParseShaderTable(L, 1, "fragment", fragSrcs))
return 0;

if (!geomSrcs.empty()) {
#if defined(__APPLE__)
// macOS via Mesa Zink / KosmicKrisp on Apple Silicon: Vulkan reports
// geometryShader = false (Metal has no GS stage). Mesa advertises
// GL_MAX_GEOMETRY_OUTPUT_VERTICES > 0 anyway, so the GL query cannot
// detect the missing capability. Strip GS so the program at least
// links; widgets that need GS-style point expansion have a Lua-layer
// NoGS fallback (see Beyond-All-Reason PR for the dual-path widgets).
GLint maxGeomOutputVerts = 0;
glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &maxGeomOutputVerts);
const GLenum err = glGetError();
LOG_L(L_WARNING, "[LuaShaders::%s] GS check: GL_MAX_GEOMETRY_OUTPUT_VERTICES=%d, glErr=0x%x, geomSrcs=%d",
__func__, maxGeomOutputVerts, err, (int)geomSrcs.size());
LOG_L(L_WARNING,
"[LuaShaders::%s] GS unconditionally stripped on macOS "
"(Metal has no GS stage). maxGeomVerts=%d",
__func__, maxGeomOutputVerts);
geomSrcs.clear();
#endif // __APPLE__
}

if (!ParseShaderTable(L, 1, "compute", compSrcs))
return 0;

Expand Down
4 changes: 3 additions & 1 deletion rts/Lua/LuaTextures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ std::string LuaTextures::Create(const Texture& tex)
} break;
}

if (glGetError() != GL_NO_ERROR) {
if (const GLenum texErr = glGetError(); texErr != GL_NO_ERROR) {
LOG_L(L_ERROR, "[LuaTextures::%s] glTexImage failed: target=0x%x size=%dx%d fmt=0x%x dataFmt=0x%x dataType=0x%x border=%d glError=0x%x",
__func__, tex.target, tex.xsize, tex.ysize, tex.format, dataFormat, dataType, tex.border, texErr);
glDeleteTextures(1, &texID);
glBindTexture(tex.target, currentBinding);
return "";
Expand Down
4 changes: 3 additions & 1 deletion rts/Rendering/GL/glxHandler.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#ifndef __APPLE__
#include "glxHandler.h"

#if !defined(HEADLESS) && !defined(_WIN32) && !defined(__APPLE__)
Expand Down Expand Up @@ -60,4 +61,5 @@ bool GLX::GetVideoMemInfoMESA(int* memInfo)
void GLX::Load(SDL_Window* window) {}
void GLX::Unload() {}
bool GLX::GetVideoMemInfoMESA(int* memInfo) { return false; }
#endif
#endif
#endif // __APPLE__
4 changes: 3 additions & 1 deletion rts/Rendering/GL/glxHandler.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#ifndef __APPLE__
#pragma once

struct SDL_Window;
Expand All @@ -10,4 +11,5 @@ struct GLX {
static bool GetVideoMemInfoMESA(int* memInfo);
private:
static inline bool supported = false;
};
};
#endif // __APPLE__
4 changes: 4 additions & 0 deletions rts/Rendering/GL/myGL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,11 @@ static bool GetVideoMemInfoATI(GLint* memInfo)
static bool GetVideoMemInfoMESA(GLint* memInfo)
{
RECOIL_DETAILED_TRACY_ZONE;
#ifndef __APPLE__
return GLX::GetVideoMemInfoMESA(memInfo);
#else
return false;
#endif
}
#endif

Expand Down
Loading