Skip to content

ruby: Update to SDL3 #1845

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
23 changes: 11 additions & 12 deletions cmake/finders/FindSDL.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ include(FindPackageHandleStandardArgs)

find_package(PkgConfig QUIET)
if(PKG_CONFIG_FOUND)
pkg_search_module(PC_SDL QUIET sdl2)
pkg_search_module(PC_SDL QUIET sdl3)
endif()

# SDL_set_soname: Set SONAME on imported library target
Expand All @@ -64,10 +64,18 @@ macro(SDL_set_soname)
unset(_result)
endmacro()

find_library(
SDL_LIBRARY
NAMES SDL3 SDL3-3.0.0 SDL3-3.0
HINTS ${PC_SDL_LIBRARY_DIRS}
PATHS ${CMAKE_SOURCE_DIR}/.deps /usr/lib /usr/local/lib
DOC "SDL location"
)

find_path(
SDL_INCLUDE_DIR
NAMES SDL.h SDL2/SDL.h
HINTS ${PC_SDL_INCLUDE_DIRS}
NAMES SDL.h SDL3/SDL.h
HINTS ${PC_SDL_INCLUDE_DIRS} ${SDL_LIBRARY}/..
PATHS ${CMAKE_SOURCE_DIR}/.deps /usr/include /usr/local/include
DOC "SDL include directory"
# "$<$<PLATFORM_ID:Darwin>:NO_DEFAULT_PATH>"
Expand All @@ -82,15 +90,6 @@ else()
set(SDL_VERSION 0.0.0)
endif()

find_library(
SDL_LIBRARY
NAMES SDL2 SDL2-2.0.0 SDL2-2.0
HINTS ${PC_SDL_LIBRARY_DIRS}
PATHS ${CMAKE_SOURCE_DIR}/.deps /usr/lib /usr/local/lib
DOC "SDL location"
# "$<$<PLATFORM_ID:Darwin>:NO_DEFAULT_PATH>"
)

if(CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin|Windows")
set(SDL_ERROR_REASON "Ensure that ares-deps are provided as part of CMAKE_PREFIX_PATH.")
elseif(CMAKE_HOST_SYSTEM_NAME MATCHES "Linux|FreeBSD")
Expand Down
3 changes: 0 additions & 3 deletions cmake/macos/defaults.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

include_guard(GLOBAL)

# Required to avoid us finding a system SDL2.framework before our provided SDL2.dylib
set(CMAKE_FIND_FRAMEWORK LAST)

# Set empty codesigning team if not specified as cache variable
if(NOT ARES_CODESIGN_TEAM)
set(ARES_CODESIGN_TEAM "" CACHE STRING "ares code signing team for macOS" FORCE)
Expand Down
2 changes: 0 additions & 2 deletions cmake/macos/helpers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,6 @@ function(_bundle_dependencies target)

if(is_system_framework OR is_xcode_framework)
continue()
elseif(is_framework)
file(REAL_PATH "../../.." library_location BASE_DIRECTORY "${imported_location}")
elseif(_required_macos VERSION_GREATER CMAKE_OSX_DEPLOYMENT_TARGET)
continue()
elseif(NOT library_type STREQUAL "STATIC_LIBRARY")
Expand Down
43 changes: 24 additions & 19 deletions ruby/audio/sdl.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include <SDL2/SDL.h>
#include <SDL3/SDL.h>

struct AudioSDL : AudioDriver {
AudioSDL& self = *this;
Expand Down Expand Up @@ -34,32 +34,32 @@ struct AudioSDL : AudioDriver {

auto clear() -> void override {
if(!ready()) return;
SDL_ClearQueuedAudio(_device);
SDL_ClearAudioStream(_stream);
}

auto output(const f64 samples[]) -> void override {
if(!ready()) return;

if(self.blocking) {
auto bytesRemaining = SDL_GetQueuedAudioSize(_device);
auto bytesRemaining = SDL_GetAudioStreamAvailable(_stream);
while(bytesRemaining > _bufferSize) {
//wait for audio to drain
auto bytesToWait = bytesRemaining - _bufferSize;
auto bytesPerSample = bitsPerSample / 8.0;
auto samplesRemaining = bytesToWait / bytesPerSample;
auto secondsRemaining = samplesRemaining / frequency;
usleep(secondsRemaining * 1000000);
bytesRemaining = SDL_GetQueuedAudioSize(_device);
bytesRemaining = SDL_GetAudioStreamAvailable(_stream);
}
}

std::unique_ptr<f32[]> output = std::make_unique<f32[]>(channels);
for(auto n : range(channels)) output[n] = samples[n];
SDL_QueueAudio(_device, &output[0], channels * sizeof(f32));
SDL_PutAudioStreamData(_stream, &output[0], channels * sizeof(f32));
}

auto level() -> f64 override {
return SDL_GetQueuedAudioSize(_device) / ((f64)_bufferSize);
return SDL_GetAudioStreamAvailable(_stream) / ((f64)_bufferSize);
}

private:
Expand All @@ -72,20 +72,24 @@ struct AudioSDL : AudioDriver {

SDL_InitSubSystem(SDL_INIT_AUDIO);

SDL_AudioSpec want{}, have{};
want.freq = frequency;
want.format = AUDIO_F32SYS;
want.channels = 2;

SDL_AudioSpec spec;
spec.format = SDL_AUDIO_F32;
spec.channels = 2;
spec.freq = frequency;
auto desired_samples = (latency * frequency) / 1000.0f;
want.samples = pow(2, ceil(log2(desired_samples))); // SDL2 requires power-of-two buffer sizes

_device = SDL_OpenAudioDevice(NULL,0,&want,&have,0);
frequency = have.freq;
channels = have.channels;
bitsPerSample = SDL_AUDIO_BITSIZE(have.format);
_bufferSize = have.size;
SDL_PauseAudioDevice(_device, 0);
string desired_samples_string = (string)desired_samples;
SDL_SetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES, desired_samples_string);

SDL_AudioStream *stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, NULL, NULL);
_device = SDL_GetAudioStreamDevice(stream);
SDL_ResumeAudioDevice(_device);
_stream = stream;
frequency = spec.freq;
channels = spec.channels;
int bufferFrameSize;
SDL_GetAudioDeviceFormat(_device, &spec, &bufferFrameSize);
bitsPerSample = SDL_AUDIO_BITSIZE(spec.format);
_bufferSize = bufferFrameSize * channels * 4;

_ready = true;
clear();
Expand All @@ -105,5 +109,6 @@ struct AudioSDL : AudioDriver {
bool _ready = false;

SDL_AudioDeviceID _device = 0;
SDL_AudioStream *_stream;
u32 _bufferSize = 0;
};
3 changes: 1 addition & 2 deletions ruby/cmake/os-macos.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ target_link_libraries(
if(SDL_FOUND)
target_link_libraries(
ruby
PRIVATE "$<LINK_LIBRARY:WEAK_LIBRARY,SDL::SDL>"
# "$<$<BOOL:${SDL_FOUND}>:SDL::SDL>"
PRIVATE "$<LINK_LIBRARY:WEAK_FRAMEWORK,SDL::SDL>"
)
endif()

Expand Down
40 changes: 21 additions & 19 deletions ruby/input/joypad/sdl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,27 @@ struct InputJoypadSDL {
}

auto poll(vector<shared_pointer<HID::Device>>& devices) -> void {
SDL_JoystickUpdate();
SDL_UpdateJoysticks();
SDL_Event event;
while(SDL_PollEvent(&event)) {
if(event.type == SDL_JOYDEVICEADDED || event.type == SDL_JOYDEVICEREMOVED) {
if(event.type == SDL_EVENT_JOYSTICK_ADDED || event.type == SDL_EVENT_JOYSTICK_REMOVED) {
enumerate();
}
}

for(auto& jp : joypads) {
for(u32 n : range(jp.hid->axes().size())) {
assign(jp, HID::Joypad::GroupID::Axis, n, (s16)SDL_JoystickGetAxis(jp.handle, n));
assign(jp, HID::Joypad::GroupID::Axis, n, (s16)SDL_GetJoystickAxis(jp.handle, n));
}

for(s32 n = 0; n < (s32)jp.hid->hats().size() - 1; n += 2) {
u8 state = SDL_JoystickGetHat(jp.handle, n >> 1);
u8 state = SDL_GetJoystickHat(jp.handle, n >> 1);
assign(jp, HID::Joypad::GroupID::Hat, n + 0, state & SDL_HAT_LEFT ? -32767 : state & SDL_HAT_RIGHT ? +32767 : 0);
assign(jp, HID::Joypad::GroupID::Hat, n + 1, state & SDL_HAT_UP ? -32767 : state & SDL_HAT_DOWN ? +32767 : 0);
}

for(u32 n : range(jp.hid->buttons().size())) {
assign(jp, HID::Joypad::GroupID::Button, n, (bool)SDL_JoystickGetButton(jp.handle, n));
assign(jp, HID::Joypad::GroupID::Button, n, (bool)SDL_GetJoystickButton(jp.handle, n));
}

devices.append(jp.hid);
Expand All @@ -59,7 +59,7 @@ struct InputJoypadSDL {
for(auto& jp : joypads) {
if(jp.hid->id() != id) continue;

SDL_JoystickRumble(jp.handle, strong, weak, 0);
SDL_RumbleJoystick(jp.handle, strong, weak, 0);
return true;
}

Expand All @@ -70,14 +70,14 @@ struct InputJoypadSDL {
terminate();
SDL_Init(SDL_INIT_EVENTS);
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
SDL_JoystickEventState(SDL_ENABLE);
//SDL_JoystickEventState(1);
enumerate();
return true;
}

auto terminate() -> void {
for(auto& jp : joypads) {
SDL_JoystickClose(jp.handle);
SDL_CloseJoystick(jp.handle);
}
joypads.reset();
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
Expand All @@ -86,31 +86,33 @@ struct InputJoypadSDL {
private:
auto enumerate() -> void {
for(auto& joypad : joypads) {
SDL_JoystickClose(joypad.handle);
SDL_CloseJoystick(joypad.handle);
}
joypads.reset();

for(u32 id : range(SDL_NumJoysticks())) {
int num_joysticks;
SDL_JoystickID *joysticks = SDL_GetJoysticks(&num_joysticks);
for(int i = 0; i < num_joysticks; i++) {
SDL_JoystickID id = joysticks[i];
Joypad jp;
jp.id = id;
jp.handle = SDL_JoystickOpen(jp.id);
jp.handle = SDL_OpenJoystick(jp.id);
if(!jp.handle) {
const char *err = SDL_GetError();
print("Error opening SDL joystick id ", id, ": ", err);
continue;
}

s32 axes = SDL_JoystickNumAxes(jp.handle);
s32 hats = SDL_JoystickNumHats(jp.handle) * 2;
s32 buttons = SDL_JoystickNumButtons(jp.handle);
s32 axes = SDL_GetNumJoystickAxes(jp.handle);
s32 hats = SDL_GetNumJoystickHats(jp.handle) * 2;
s32 buttons = SDL_GetNumJoystickButtons(jp.handle);
if(axes < 0 || hats < 0 || buttons < 0) {
const char *err = SDL_GetError();
print("Error retrieving SDL joystick information for device ", jp.handle, " at index ", id, ": ", err);
continue;
}

u16 vid = SDL_JoystickGetVendor(jp.handle);
u16 pid = SDL_JoystickGetProduct(jp.handle);
u16 vid = SDL_GetJoystickVendor(jp.handle);
u16 pid = SDL_GetJoystickProduct(jp.handle);
if(vid == 0) vid = HID::Joypad::GenericVendorID;
if(pid == 0) pid = HID::Joypad::GenericProductID;

Expand All @@ -124,7 +126,7 @@ struct InputJoypadSDL {

joypads.append(jp);
}

SDL_JoystickUpdate();
SDL_free(joysticks);
SDL_UpdateJoysticks();
}
};
2 changes: 1 addition & 1 deletion ruby/input/sdl.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include <SDL2/SDL.h>
#include <SDL3/SDL.h>

#if defined(PLATFORM_WINDOWS)
#include "shared/rawinput.cpp"
Expand Down
Loading