Skip to content
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

add initial playdate support #5474

Closed
wants to merge 6 commits into from

Conversation

ericlewis
Copy link

@ericlewis ericlewis commented Mar 30, 2022

Description

This PR adds initial support for the Playdate platform.

Supported features:

  • video
  • joystick
  • power
  • sensor
  • timer

Questions

This is my first time creating any sort of patch for SDL2 let alone adding support for a new hardware platform, so I am very open to any and all suggestions. It is quite likely things are incorrect / not fully supported. I also have some questions up-front:

  • How do I go about adding this to the config/make files?
    • Playdate has a simulator that runs on window/macOS, as well as the target arm device
    • The way I currently am able to compile is by passing the correct flags (TARGET_PLAYDATE or PLAYDATE)
    • Each target uses a completely different toolchain, the hardware toolchain is specific
  • Any advice on having the joystick also support game controller?
  • Any advice on tackling audio support?
  • Would it be preferred that these are smaller patches?
  • Is there a test suite that must pass? That may be a challenge.
  • Limited testing on actual hardware currently, would it be better to wait to upstream until it is more thoroughly tested?
  • Where would something like the crank fall under in hardware support? Sensor? Joystick?
  • What do we do about main support? Playdate has its own run loop, so setting up for playdate is slightly different.
  • There are some syscalls needed that playdate doesn't have which I implemented here in src/main/playdate, is this an appropriate place for including them?
  • I am curious about openGL/gles support, but lack the knowledge to understand what is required for supporting those platforms. There isn't really any hardware accel, but software based rendering might be fine.
  • Renderer seems close to how some things are drawn on playdate via draw commands, would it make sense to add a playdate renderer?
  • This requires an imported pd_api.h from the pd sdk that must be included in order to build, what is the best way to provide this?
  • advice on how to better work on SDL2 locally, I currently just copy the folder into a project and setup the project make file manually
  • playdate has a 1bit b&w display and surface input gets converted and dithered automatically by the driver, what would be a good way to hint to the developer that this is happening?
  • Similar to above, what would be an idiomatic way of allowing developers to control the style of dithering?
  • There are other edge cases too, is there a way to provide a logging primitive to SDL as well? printf isn't supported for instance.

Notes

  • I am happy to convert this to a draft if it is more appropriate to do so.
  • The SDL_config_playdate.h is kind of a mess.. advice on how to better orient this and handle things would be awesome.

Comment on lines +32 to +34
#if defined(PLAYDATE)
#include "SDL_config_playdate.h"
#elif defined(__WIN32__)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added this to the top so it gets caught before host platforms - the config file unsets platform specific flags

@slouken
Copy link
Collaborator

slouken commented Mar 30, 2022

  • How do I go about adding this to the config/make files?

Right now we support both autotools and CMake. If your build environment is primarily CMake, then it's fine just add it there. I don't know CMake, so I don't have any advice on the implementation details, but I imagine you'd just follow the pattern for other platforms and possibly have a CMake define that turns this support on.

  • Any advice on having the joystick also support game controller?

Go ahead and add a section to SDL_gamecontrollerdb.h with your platform define (there's typically one added for each platform in SDL_platform.h, e.g. __PLAYDATE__)

  • Any advice on tackling audio support?

@icculus?

  • Would it be preferred that these are smaller patches?

One big PR for the initial platform support is fine, then additional fixes should each have their own PR.

  • Is there a test suite that must pass? That may be a challenge.

Not a formal suite, but there's some automated and manual tests in the test directory that are useful in validating platform functionality.

  • Limited testing on actual hardware currently, would it be better to wait to upstream until it is more thoroughly tested?

Yes, this should wait until it's more mature and has good testing on actual hardware before we merge it. Feel free to update this PR iterating until you're comfortable with it. Converting it to a draft now and then converting back when you're ready will be a good way to signal to us that you consider it ready. I imagine we probably won't have time to look at this much before then.

  • Where would something like the crank fall under in hardware support? Sensor? Joystick?

I don't know how the data is represented, but it looks like a custom sensor type is probably best.

  • What do we do about main support? Playdate has its own run loop, so setting up for playdate is slightly different.

SDL games are in charge of their own run loop, so you'll need to find some way to support that. Putting the relevant code in src/main/playdate is fine. Android, for example, creates a thread where the SDL main loop goes, and has interop between that thread and the main process. That road is fraught with danger, but is an option if that's the only way to make it work.

  • There are some syscalls needed that playdate doesn't have which I implemented here in src/main/playdate, is this an appropriate place for including them?

Usually those would go in src/core/playdate

  • I am curious about openGL/gles support, but lack the knowledge to understand what is required for supporting those platforms. There isn't really any hardware accel, but software based rendering might be fine.

Just leave that unimplemented. It sounds the software renderer is the way to go here.

  • Renderer seems close to how some things are drawn on playdate via draw commands, would it make sense to add a playdate renderer?

Yes, if it has full support for SDL's rendering capabilities. You might be better off just using SDL's software renderer instead.

  • This requires an imported pd_api.h from the pd sdk that must be included in order to build, what is the best way to provide this?

You should create a file docs/README-playdate.md that has any information needed to set up the build environment and run applications. Having a step of setting up include paths or copying a required header is fine.

  • advice on how to better work on SDL2 locally, I currently just copy the folder into a project and setup the project make file manually

That's probably fine. :)

  • playdate has a 1bit b&w display and surface input gets converted and dithered automatically by the driver, what would be a good way to hint to the developer that this is happening?

Documentation. If someone is building for the platform they should be aware of what's happening and how to control it.

  • Similar to above, what would be an idiomatic way of allowing developers to control the style of dithering?

Use an SDL hint. There are lots of examples in SDL_hints.h

  • There are other edge cases too, is there a way to provide a logging primitive to SDL as well? printf isn't supported for instance.

Yes, SDL_Log() is the standard way of providing logging. You can extend SDL_LogOutput() with the required functionality.

  • The SDL_config_playdate.h is kind of a mess.. advice on how to better orient this and handle things would be awesome.

What you've done is fine. The config files are generally not meant to be human readable for people not familiar with SDL's internals.

@ericlewis ericlewis marked this pull request as draft March 30, 2022 19:31
@ericlewis
Copy link
Author

SDL games are in charge of their own run loop, so you'll need to find some way to support that. Putting the relevant code in src/main/playdate is fine. Android, for example, creates a thread where the SDL main loop goes, and has interop between that thread and the main process. That road is fraught with danger, but is an option if that's the only way to make it work.

Thank you for the thoughtful response! I think I need more clarification as to what the SDL main loop is doing/is for. I've ignored it thus far without issue, but that seems problematic. Is it a way to call a user defined entry point or something? Is there something SDL has to do other than say "main is ready"? For now I just stubbed it, but it'll never get called anyway. Would it be better to user the platforms version of main to then call a user implemented main once it is setup?

@slouken
Copy link
Collaborator

slouken commented Mar 30, 2022

Thank you for the thoughtful response! I think I need more clarification as to what the SDL main loop is doing/is for. I've ignored it thus far without issue, but that seems problematic. Is it a way to call a user defined entry point or something? Is there something SDL has to do other than say "main is ready"? For now I just stubbed it, but it'll never get called anyway. Would it be better to user the platforms version of main to then call a user implemented main once it is setup?

I'd have to understand better how the platform works, but if you're not doing anything and the application is entering it's main() function and everything is working, then you may not need the SDL main loop stuff at all. That's only needed if there's platform specific prologue that needs to happen before the application main(). In that case, the application main is renamed SDL_main() and called from the prologue code. The Windows code is a good example of that, where there's a WinMain() that does some setup and then calls the application SDL_main() function. Again, maybe you don't need that at all?

@icculus
Copy link
Collaborator

icculus commented Mar 30, 2022

Any advice on tackling audio support?

The likely most direct example is the "arts" driver, which is used for an extremely basic (and obsolete) network audio server;

https://github.com/libsdl-org/SDL/blob/7e15ad2fc4f610482c2f7b23a6fb2838c8759f93/src/audio/arts/SDL_artsaudio.c

Most of the heavy lifting is going to happen in the OpenDevice implementation.

The primary goals are to allocate driver-specific data...

/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_zerop(this->hidden);

...find the closest audio format the hardware supports to what was requested by the app...

/* Try for a closest match on audio format */
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
#endif
switch (test_format) {
case AUDIO_U8:
case AUDIO_S16LSB:
break;
default:
continue;
}
break;
}
if (!test_format) {
return SDL_SetError("%s: Unsupported audio format", "arts");
}
this->spec.format = test_format;
bits = SDL_AUDIO_BITSIZE(test_format);

...prep the hardware to play sound...

if ((rc = SDL_NAME(arts_init) ()) != 0) {
return SDL_SetError("Unable to initialize ARTS: %s",
SDL_NAME(arts_error_text) (rc));
}
if (!ARTS_Suspend()) {
return SDL_SetError("ARTS can not open audio device");
}
this->hidden->stream = SDL_NAME(arts_play_stream) (this->spec.freq,
bits,
this->spec.channels,
"SDL");
/* Play nothing so we have at least one write (server bug workaround). */
SDL_NAME(arts_write) (this->hidden->stream, "", 0);

...and make sure you have a mixing buffer...

/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);

Note that in there it sets this->spec's fields to values the hardware actually wants to be fed. If these are different than what the app wanted, SDL will either tell the app there were differences or transparently convert audio to this format on behalf of the app. So if the Playdate can only take audio in exactly one format/number of channels/sample rate, that's okay, SDL will manage that detail for you and the app.

Once you're up and running, audio runs in a background thread managed by SDL. If the Playdate doesn't have threads, we're going to have to talk further about how to deal with this.

That background thread, more or less, will just keep calling your WaitDevice and PlayDevice implementations in a loop...

static void
ARTS_WaitDevice(_THIS)
{
Sint32 ticks;
/* Check to see if the thread-parent process is still alive */
{
static int cnt = 0;
/* Note that this only works with thread implementations
that use a different process id for each thread.
*/
/* Check every 10 loops */
if (this->hidden->parent && (((++cnt) % 10) == 0)) {
if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) {
SDL_OpenedAudioDeviceDisconnected(this);
}
}
}
/* Use timer for general audio synchronization */
ticks =
((Sint32) (this->hidden->next_frame - SDL_GetTicks())) - FUDGE_TICKS;
if (ticks > 0) {
SDL_Delay(ticks);
}
}

static void
ARTS_PlayDevice(_THIS)
{
/* Write the audio data */
int written = SDL_NAME(arts_write) (this->hidden->stream,
this->hidden->mixbuf,
this->hidden->mixlen);
/* If timer synchronization is enabled, set the next write frame */
if (this->hidden->frame_ticks) {
this->hidden->next_frame += this->hidden->frame_ticks;
}
/* If we couldn't write, assume fatal error for now */
if (written < 0) {
SDL_OpenedAudioDeviceDisconnected(this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
}

...WaitDevice is meant to block until more audio can be fed to the device, PlayDevice is meant to feed the audio.

GetDeviceBuf is meant to provide memory where SDL can write audio buffers:

static Uint8 *
ARTS_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}

Most cases just have the implementation allocate a block of memory during Open, but some drivers can provide a block of their own that the OS or hardware reads out of directly, saving the need to do an extra copy.

Is there a microphone on the Playdate? If not, anything that refers to "capture" (audio recording) can be ignored. Otherwise, there are a few more methods to implement, but that can wait until playback works.

@icculus
Copy link
Collaborator

icculus commented Mar 30, 2022

I don't know how the data is represented, but it looks like a custom sensor type is probably best.

...maybe a mouse that only reports relative motion on an infinite Y axis?

@sgeos
Copy link

sgeos commented Mar 31, 2022

I don't know how the data is represented, but it looks like a custom sensor type is probably best.

...maybe a mouse that only reports relative motion on an infinite Y axis?

Re: Crank

The official Playdate API reports values as an absolute angle or a relative change in angle. Could it make sense to report the angles as the X and Y values of an analog stick or mouse?
C API - https://sdk.play.date/inside-playdate-with-c/#_crank
Lua API - https://sdk.play.date/inside-playdate/#crank

The crank can also be docked or undocked. Docked status could be a button. Having said that, it could also be a mouse button. In that case, the crank could just be a mouse.

For rudimentary interoperability and testing on PC, it might make sense to map the crank docked status to the left mouse click (mouse down == undocked, mouse up = docked) and the crank angles to the mouse wheel. SDL's mouse wheel model has x and y values which could be used for absolute (y/preciseY) and relative angles (x/preciseX; positive=clockwise). In this case, just reset the absolute angle to 0 every time time crank is undocked. Does this sound reasonable?

@sgeos
Copy link

sgeos commented Mar 31, 2022

Thank you for the thoughtful response! I think I need more clarification as to what the SDL main loop is doing/is for. I've ignored it thus far without issue, but that seems problematic. Is it a way to call a user defined entry point or something? Is there something SDL has to do other than say "main is ready"? For now I just stubbed it, but it'll never get called anyway. Would it be better to user the platforms version of main to then call a user implemented main once it is setup?

I'd have to understand better how the platform works, but if you're not doing anything and the application is entering it's main() function and everything is working, then you may not need the SDL main loop stuff at all. That's only needed if there's platform specific prologue that needs to happen before the application main(). In that case, the application main is renamed SDL_main() and called from the prologue code. The Windows code is a good example of that, where there's a WinMain() that does some setup and then calls the application SDL_main() function. Again, maybe you don't need that at all?

Re: main() not available on Playdate

There is no main() function available to programmers on the Playdate. The Playdate C API has an eventHandler() function that can be used to set up an update() function. My understanding is that the game is loaded as a dynamic library and the firmware then becomes responsible for calling the eventHandler() and update() functions at the appropriate time. Strictly speaking, eventHandler() is the application entry point.
https://sdk.play.date/1.9.3/Inside%20Playdate%20with%20C.html#_game_initialization

A minimal example of the Playdate game structure looks something like this.

#include "pd_api.h"

struct ProgramState {
  PlaydateAPI *pd;
  // ... other fields here ...
};

void initProgramState(struct ProgramState *ps, PlaydateAPI *pd)
{
  ps->pd = pd;
  // ... initialize other fields here ...
}

static int update(void* userdata)
{
  struct ProgramState *ps = (struct ProgramState *)userdata;
  PlaydateAPI *pd = ps->pd;
  // ... game logic here ...
  return 1;
}

#ifdef _WINDLL
__declspec(dllexport)
#endif
int eventHandler(PlaydateAPI* pd, PDSystemEvent event, uint32_t arg)
{
  (void)arg; // only used for kEventKeyPressed == event
  static struct ProgramState *ps = NULL;

  switch (event) {
    case kEventInit:
      ps = pd->system->realloc(ps, sizeof(struct ProgramState));
      initProgramState(ps, pd);
      pd->system->setUpdateCallback(update, (void *)ps);
      break;
    case kEventTerminate:
      pd->system->realloc(ps, 0);
      ps = NULL;
      break;
    default:
      // do nothing
    break;
  };

  return 0;
}

@sgeos
Copy link

sgeos commented Apr 1, 2022

Any advice on tackling audio support?

SNIP

Once you're up and running, audio runs in a background thread managed by SDL. If the Playdate doesn't have threads, we're going to have to talk further about how to deal with this.

SNIP

Looks like further discussion is necessary. The Playdate does not support threads. See also.

@icculus
Copy link
Collaborator

icculus commented Apr 1, 2022

Looks like further discussion is necessary. The Playdate does not support threads. See also.

To be clear, though, we also work correctly on single-threaded Emscripten, so while SDL will try to spin a thread by default, audio backends can be made to manage this on their own.

In Emscripten's case, we mark the backend as "providing it's own thread" ...

/* no threads here */
impl->LockDevice = impl->UnlockDevice = EMSCRIPTENAUDIO_LockOrUnlockDeviceWithNoMixerLock;
impl->ProvidesOwnCallbackThread = SDL_TRUE;

...so SDL doesn't even try to create a thread there. While this was meant for things like CoreAudio where the OS spins a thread for us, it's close enough. :) Then the emscripten backend a callback that fires when the main thread is idle, and the browser knows to fire it regularly. I assume Playdate will do something similar.

Although it might have to do some tapdancing to manage format conversion, etc, so you might have to wrap some SDL_AudioStreams around things where SDL_RunAudio would have managed it for you otherwise.

Here's the function CoreAudio calls from the system-created thread:

/* The AudioQueue callback */
static void
outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
{
SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
if (SDL_AtomicGet(&this->hidden->shutdown)) {
return; /* don't do anything. */
}
if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
/* Supply silence if audio is not enabled or paused */
SDL_memset(inBuffer->mAudioData, this->spec.silence, inBuffer->mAudioDataBytesCapacity);
} else if (this->stream) {
UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
Uint8 *ptr = (Uint8 *) inBuffer->mAudioData;
while (remaining > 0) {
if (SDL_AudioStreamAvailable(this->stream) == 0) {
/* Generate the data */
SDL_LockMutex(this->mixer_lock);
(*this->callbackspec.callback)(this->callbackspec.userdata,
this->hidden->buffer, this->hidden->bufferSize);
SDL_UnlockMutex(this->mixer_lock);
this->hidden->bufferOffset = 0;
SDL_AudioStreamPut(this->stream, this->hidden->buffer, this->hidden->bufferSize);
}
if (SDL_AudioStreamAvailable(this->stream) > 0) {
int got;
UInt32 len = SDL_AudioStreamAvailable(this->stream);
if (len > remaining)
len = remaining;
got = SDL_AudioStreamGet(this->stream, ptr, len);
SDL_assert((got < 0) || (got == len));
if (got != len) {
SDL_memset(ptr, this->spec.silence, len);
}
ptr = ptr + len;
remaining -= len;
}
}
} else {
UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
Uint8 *ptr = (Uint8 *) inBuffer->mAudioData;
while (remaining > 0) {
UInt32 len;
if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
/* Generate the data */
SDL_LockMutex(this->mixer_lock);
(*this->callbackspec.callback)(this->callbackspec.userdata,
this->hidden->buffer, this->hidden->bufferSize);
SDL_UnlockMutex(this->mixer_lock);
this->hidden->bufferOffset = 0;
}
len = this->hidden->bufferSize - this->hidden->bufferOffset;
if (len > remaining) {
len = remaining;
}
SDL_memcpy(ptr, (char *)this->hidden->buffer +
this->hidden->bufferOffset, len);
ptr = ptr + len;
remaining -= len;
this->hidden->bufferOffset += len;
}
}
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity;
}

...as you can see, it's slightly more involved than other platforms that just need to dump audio data to the hardware, because SDL handled all this at a higher level from its own thread for them. But it's not too awful to manage.

@ericlewis
Copy link
Author

ericlewis commented Apr 1, 2022

Looks like further discussion is necessary. The Playdate does not support threads. See also.

To be clear, though, we also work correctly on single-threaded Emscripten, so while SDL will try to spin a thread by default, audio backends can be made to manage this on their own.

In Emscripten's case, we mark the backend as "providing it's own thread" ...

/* no threads here */
impl->LockDevice = impl->UnlockDevice = EMSCRIPTENAUDIO_LockOrUnlockDeviceWithNoMixerLock;
impl->ProvidesOwnCallbackThread = SDL_TRUE;

...so SDL doesn't even try to create a thread there. While this was meant for things like CoreAudio where the OS spins a thread for us, it's close enough. :) Then the emscripten backend a callback that fires when the main thread is idle, and the browser knows to fire it regularly. I assume Playdate will do something similar.

Although it might have to do some tapdancing to manage format conversion, etc, so you might have to wrap some SDL_AudioStreams around things where SDL_RunAudio would have managed it for you otherwise.

Here's the function CoreAudio calls from the system-created thread:

/* The AudioQueue callback */
static void
outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
{
SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
if (SDL_AtomicGet(&this->hidden->shutdown)) {
return; /* don't do anything. */
}
if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
/* Supply silence if audio is not enabled or paused */
SDL_memset(inBuffer->mAudioData, this->spec.silence, inBuffer->mAudioDataBytesCapacity);
} else if (this->stream) {
UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
Uint8 *ptr = (Uint8 *) inBuffer->mAudioData;
while (remaining > 0) {
if (SDL_AudioStreamAvailable(this->stream) == 0) {
/* Generate the data */
SDL_LockMutex(this->mixer_lock);
(*this->callbackspec.callback)(this->callbackspec.userdata,
this->hidden->buffer, this->hidden->bufferSize);
SDL_UnlockMutex(this->mixer_lock);
this->hidden->bufferOffset = 0;
SDL_AudioStreamPut(this->stream, this->hidden->buffer, this->hidden->bufferSize);
}
if (SDL_AudioStreamAvailable(this->stream) > 0) {
int got;
UInt32 len = SDL_AudioStreamAvailable(this->stream);
if (len > remaining)
len = remaining;
got = SDL_AudioStreamGet(this->stream, ptr, len);
SDL_assert((got < 0) || (got == len));
if (got != len) {
SDL_memset(ptr, this->spec.silence, len);
}
ptr = ptr + len;
remaining -= len;
}
}
} else {
UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
Uint8 *ptr = (Uint8 *) inBuffer->mAudioData;
while (remaining > 0) {
UInt32 len;
if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
/* Generate the data */
SDL_LockMutex(this->mixer_lock);
(*this->callbackspec.callback)(this->callbackspec.userdata,
this->hidden->buffer, this->hidden->bufferSize);
SDL_UnlockMutex(this->mixer_lock);
this->hidden->bufferOffset = 0;
}
len = this->hidden->bufferSize - this->hidden->bufferOffset;
if (len > remaining) {
len = remaining;
}
SDL_memcpy(ptr, (char *)this->hidden->buffer +
this->hidden->bufferOffset, len);
ptr = ptr + len;
remaining -= len;
this->hidden->bufferOffset += len;
}
}
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity;
}

...as you can see, it's slightly more involved than other platforms that just need to dump audio data to the hardware, because SDL handled all this at a higher level from its own thread for them. But it's not too awful to manage.

Single thread will have to be the way to go. There is a way to create an audio buffer than can then be played, the buffer itself doesn't get copied so it might be possible to continuously update said buffer. There is also a callback from the audio player that indicates when playback is finished. The sound formats playback supports is listed below:

kSound8bitMono = 0,
kSound8bitStereo = 1,
kSound16bitMono = 2,
kSound16bitStereo = 3,
kSoundADPCMMono = 4,
kSoundADPCMStereo = 5

Not entirely sure what these actually equate to yet. I will probably start by seeing how writing to the buffer works anyway. That said, I don't feel that doing audio right now is necessary to upstreaming what we have so far.

On the note of the single threadedness of playdate, there is a main loop and it's called as fast as possible to schedule any and all work that must be done. I have noticed however that audio will remain playing whilst doing other things, so there is some amount of threading under the hood. Not sure if this makes any difference.

@icculus
Copy link
Collaborator

icculus commented Apr 5, 2022

@ericlewis Is there a basic HOWTO on building this? Is it "just download the SDK and click this thing?" or it is using CMake, or something else?

@icculus icculus self-assigned this Apr 5, 2022
@ericlewis
Copy link
Author

@ericlewis Is there a basic HOWTO on building this? Is it "just download the SDK and click this thing?" or it is using CMake, or something else?

I will try to do a write up for that soon or I can share a makefile. One problem is it requires a single line patch in the SDK currently, which seems out of scope for this and I am still investigating how to not need such a change. The way this is built will be using a cmake or make file, in my demo project the makefile looks like this:

HEAP_SIZE      = 8388208
STACK_SIZE     = 61800

PRODUCT = gnu.pdx

SDK = ${PLAYDATE_SDK_PATH}
ifeq ($(SDK),)
	SDK = $(shell egrep '^\s*SDKRoot' ~/.Playdate/config | head -n 1 | cut -c9-)
endif

ifeq ($(SDK),)
$(error SDK path not found; set ENV value PLAYDATE_SDK_PATH)
endif

SRC = \
	SDL/src/stdlib/SDL_malloc.c \
	SDL/src/main/playdate/SDL_playdate_main.c \
	SDL/src/SDL.c \
	SDL/src/SDL_assert.c \
	SDL/src/SDL_dataqueue.c \
	SDL/src/SDL_error.c \
	SDL/src/SDL_hints.c \
	SDL/src/SDL_log.c \
	SDL/src/audio/SDL_audio.c \
	SDL/src/audio/SDL_mixer.c \
	SDL/src/audio/SDL_wave.c \
	SDL/src/audio/SDL_audiocvt.c \
	SDL/src/audio/SDL_audiotypecvt.c \
	SDL/src/audio/dummy/SDL_dummyaudio.c \
	SDL/src/atomic/SDL_atomic.c \
	SDL/src/atomic/SDL_spinlock.c \
	SDL/src/cpuinfo/SDL_cpuinfo.c \
	SDL/src/events/imKStoUCS.c \
	SDL/src/events/SDL_clipboardevents.c \
	SDL/src/events/SDL_displayevents.c \
	SDL/src/events/SDL_dropevents.c \
	SDL/src/events/SDL_events.c \
	SDL/src/events/SDL_gesture.c \
	SDL/src/events/SDL_keyboard.c \
	SDL/src/events/SDL_mouse.c \
	SDL/src/events/SDL_quit.c \
	SDL/src/events/SDL_touch.c \
	SDL/src/events/SDL_windowevents.c \
	SDL/src/file/SDL_rwops.c \
	SDL/src/joystick/SDL_gamecontroller.c \
	SDL/src/joystick/SDL_joystick.c \
	SDL/src/joystick/virtual/SDL_virtualjoystick.c \
	SDL/src/joystick/playdate/SDL_sysjoystick.c \
	SDL/src/power/playdate/SDL_syspower.c \
	SDL/src/power/SDL_power.c \
	SDL/src/render/SDL_d3dmath.c \
	SDL/src/render/SDL_render.c \
	SDL/src/render/SDL_yuv_sw.c \
	SDL/src/render/software/SDL_drawpoint.c \
	SDL/src/render/software/SDL_blendfillrect.c \
	SDL/src/render/software/SDL_blendline.c \
	SDL/src/render/software/SDL_blendpoint.c \
	SDL/src/render/software/SDL_drawline.c \
	SDL/src/render/software/SDL_render_sw.c \
	SDL/src/render/software/SDL_rotate.c \
	SDL/src/render/software/SDL_triangle.c \
	SDL/src/sensor/playdate/SDL_playdatesensor.c \
	SDL/src/sensor/SDL_sensor.c \
	SDL/src/stdlib/SDL_crc32.c \
	SDL/src/stdlib/SDL_getenv.c \
	SDL/src/stdlib/SDL_iconv.c \
	SDL/src/stdlib/SDL_qsort.c \
	SDL/src/stdlib/SDL_stdlib.c \
	SDL/src/stdlib/SDL_string.c \
	SDL/src/stdlib/SDL_strtokr.c \
	SDL/src/libm/e_atan2.c \
	SDL/src/libm/e_exp.c \
	SDL/src/libm/e_fmod.c \
	SDL/src/libm/e_log.c \
	SDL/src/libm/e_log10.c \
	SDL/src/libm/e_pow.c \
	SDL/src/libm/e_rem_pio2.c \
	SDL/src/libm/e_sqrt.c \
	SDL/src/libm/k_cos.c \
	SDL/src/libm/k_rem_pio2.c \
	SDL/src/libm/k_sin.c \
	SDL/src/libm/k_tan.c \
	SDL/src/libm/s_atan.c \
	SDL/src/libm/s_copysign.c \
	SDL/src/libm/s_cos.c \
	SDL/src/libm/s_fabs.c \
	SDL/src/libm/s_floor.c \
	SDL/src/libm/s_scalbn.c \
	SDL/src/libm/s_sin.c \
	SDL/src/libm/s_tan.c \
	SDL/src/thread/SDL_thread.c \
	SDL/src/thread/generic/SDL_syscond.c \
	SDL/src/thread/generic/SDL_sysmutex.c \
	SDL/src/thread/generic/SDL_syssem.c \
	SDL/src/thread/generic/SDL_systhread.c \
	SDL/src/thread/generic/SDL_systls.c \
	SDL/src/timer/SDL_timer.c \
	SDL/src/timer/playdate/SDL_systimer.c \
	SDL/src/video/SDL_blit.c \
	SDL/src/video/SDL_blit_0.c \
	SDL/src/video/SDL_blit_1.c \
	SDL/src/video/SDL_blit_A.c \
	SDL/src/video/SDL_blit_auto.c \
	SDL/src/video/SDL_blit_copy.c \
	SDL/src/video/SDL_blit_N.c \
	SDL/src/video/SDL_blit_slow.c \
	SDL/src/video/SDL_bmp.c \
	SDL/src/video/SDL_clipboard.c \
	SDL/src/video/SDL_egl.c \
	SDL/src/video/SDL_fillrect.c \
	SDL/src/video/SDL_pixels.c \
	SDL/src/video/SDL_rect.c \
	SDL/src/video/SDL_RLEaccel.c \
	SDL/src/video/SDL_shape.c \
	SDL/src/video/SDL_stretch.c \
	SDL/src/video/SDL_surface.c \
	SDL/src/video/SDL_video.c \
	SDL/src/video/SDL_vulkan_utils.c \
	SDL/src/video/SDL_yuv.c \
	SDL/src/video/yuv2rgb/yuv_rgb.c \
	SDL/src/video/playdate/SDL_playdate_events.c \
	SDL/src/video/playdate/SDL_playdate_framebuffer.c \
	SDL/src/video/playdate/SDL_playdate_video.c \
	main.c

ASRC = # setup.s

# List all user directories here
UINCDIR = SDL/include

# List all user C define here, like -D_DEBUG=1
UDEFS =

# Define ASM defines here
UADEFS =

# List the user directory to look for the libraries here
DINCDIR = SDL/include

# List all user libraries here
ULIBS =

CLANGFLAGS = -DPLAYDATE=1 # needed for SDL2

include $(SDK)/C_API/buildsupport/common.mk

SDL is just copied into the same directory as the project and then you compile and it should work. But I have not done much clean room testing on this to ensure it does work that easily.

@ericlewis
Copy link
Author

I have a device now. Let the fun begin!

capehill added a commit to AmigaPorts/SDL that referenced this pull request Jan 20, 2023
* Add a hint for D3D9Ex to avoid having to choose at compile-time

* Use MSVC _byteswap intrinsics for SDL byteswapping functions

This generates bswap on x86/x64 and rev on ARM

* Fixed bug 5440 - MacCatalyst build failures

C.W. Betts

I tested building commit http://hg.libsdl.org/SDL/rev/55cdb379e866 on Mac Catalyst and found some issues:

* MTLFeatureSet_iOS_* enums aren't available under Mac Catalyst.
* OpenGL ES is unavailable under Mac Catalyst.
* Some Metal features are available under Catalyst but not iOS, such as displaySyncEnabled.
* Set Metal as the default renderer on Mac Catalyst

Attaching a patch that will make SDL2 build for Mac Catalyst.

* Use specific acquire and release variants of InterlockedExchange on ARM

_InterlockedExchange_rel() is required for correctness on ARM because
the _ReadWriteBarrier() macro is only a compiler memory barrier, not a
hardware memory barrier. Due to ARM's relaxed memory model, this means
the '*lock = 0' write may be observed before the operations inside the
lock, causing possible corruption of data protected by the lock.

_InterlockedExchange_acq() is more efficient on ARM because it avoids an
expensive full memory barrier that _InterlockedExchange() does.

* Implement SDL_MostSignificantBitIndex32 using MSVC intrinsics

* consistently use TEXT() macro with LoadLibrary() and GetModuleHandle()

cf. bug libsdl-org#5435.

* SDL_wasapi_win32.c (WASAPI_PlatformThreadInit): use L instead of TEXT()

because AvSetMmThreadCharacteristicsW specifically accepts WCHAR* input
cf. bug libsdl-org#5435.

* SDL_dinputjoystick.c (IsXInputDevice): adjust to be ANSI/UNICODE-agnostic

cf. bug libsdl-org#5435.

* RAWINPUT_InitWindowsGamingInput: change pNamespace from LPTSTR to PCWSTR

because WindowsCreateStringReference specifically accepts const WCHAR *
- WGI_JoystickInit(): ditto.

cf. bug libsdl-org#5435.

* SDL_windowswindow.c (SDL_HelperWindowCreate): adjust for ANSI/UNICODE:

change SDL_HelperWindowClassName and SDL_HelperWindowName from WCHAR *
to be const TCHAR*

cf. bug libsdl-org#5435.

* SDL_windowsjoystick.c (SDL_CreateDeviceNotification): use L, not TEXT()

cf. bug libsdl-org#5435.

* simplify Watcom implementation of SDL_MostSignificantBitIndex32()

* move SDL_tcsstr definition to core/windows/SDL_windows.h

* make ANSI/UNICODE versions of WIN??UTF8 macros individually available.

* use WIN_StringToUTF8W macro instead of WIN_StringToUTF8, where needed:

i.e. where the string is known guaranteed to be WCHAR*, in:
- SDL_dinputjoystick.c (WIN_IsXInputDevice): VARIANT->var is BSTR (WCHAR*)
- SDL_rawinputjoystick.c (RAWINPUT_AddDevice): string is WCHAR*
- SDL_windows_gaming_input.c (IEventHandler_CRawGameControllerVtbl_InvokeAdded):
  string is WCHAR*

There should be more of these..

* SDL_windows_main.c: use new WIN_StringToUTF8W macro

* Valve contributed code is under the Zlib license

* Allow setting the player index to -1, which turns off the player LED for PS5 controllers

* Fixed detection of the Wooting Two keyboard, which shows up as an Xbox 360 controller

* Add SDL_UpdateNVTexture() to update NV12/21 Texture (bug libsdl-org#5430)
for renderer software, opengl, and opengles2

* Fixed invalid read in yuv_rgb_sse() (see bug libsdl-org#5430)

* Add SDL_UpdateNVTexture for d3d11 (bug libsdl-org#5430)
(not tested)

* Fix compilation (implicit declaration of function) (see bug libsdl-org#5430)

* Fix compilation on Window10 (see bug libsdl-org#5430)

* Add SDL_UpdateNVTexture for META (bug libsdl-org#5430)
(not tested)

* Fix unused variable warning on METAL (see bug libsdl-org#5430)

* wmmsg.h: constified wmtab

* ran gendynapi.pl after SDL_UpdateNVTexture addition

* use WIN_StringToUTF8W instead of WIN_StringToUTF8 where needed (#2)

cf. bug libsdl-org#5435.
- SDL_wasapi_win32.c (GetWasapiDeviceName): pwszVal is WCHAR*
- windows/SDL_sysfilesystem.c (SDL_GetBasePath, SDL_GetPrefPath)
- windows/SDL_sysurl.c (SDL_SYS_OpenURL): wurl is WCHAR*
- SDL_windowssensor.c (ConnectSensor): bstr_name is WCHAR*
- windows/SDL_systhread.c (SDL_SYS_SetupThread): strw is WCHAR*

* video/windows: ANSI/UNICODE updates (cf. bug 5435):

- explicitly use UNICODE versions of DrawText, EnumDisplaySettings,
  EnumDisplayDevices, and CreateDC: the underlying structures have
  WCHAR strings.
- change WIN_UpdateDisplayMode and WIN_GetDisplayMode() to accept
  LPCWSTR instead of LPCTSTR for the same reason.
- change WIN_StringToUTF8 and WIN_UTF8ToString to the explicit 'W'
  versions where appropriate.

* Update config.guess and config.sub from mainstream.

Recognizes riscv32be and riscv64be.

* Add more SDL_HAVE_YUV defines

* Fix D3D11 UpdateNVTexture (bug libsdl-org#5430)

* Fix software UpdateNVTexture non fullscreen (bug libsdl-org#5430)

* Fix D3D11 UpdateTextureNV in non fullscreen (bug libsdl-org#5430)

* [KMS/DRM] Rewrite KMSDRM_LEGACY backend to accomodate Vulkan compatibility. Fix several bugs on that backend.

* fix build after commit 26e76e851774

* [KMS/DRM] Add Vulkan suport to the KMSDRM_LEGACY backend.Minor text spacing tweaks for better readability. Comment out unused function.

* [KMS/DRM] Add the missing files for Vulkan support to the KMSDRM_LEGACY backend, had forgotted to do -hg add-.

* [KMS/DRM] Correct drmModeSetCursor() dimensions.

* update config.guess and config.sub from mainstream.

* [KMS/DRM] Don't use primary plane for scaling because that's unsupported on most LEGACY-only HW.

* Fixed building when SDL_LIBUSB_DYNAMIC is defined

* Fixed bug 5449 - SDL_DROPFILE update mouse location of drop in Cocoa

Dominik Reichardt

Exult (http://exult.info) has an editor app that uses GTK+2. Up to now we were using X's drag'n'drop to allow dropping of assets from the editor onto Exult.
There is now an experimental branch that makes use of SDL_DROPFILE. That works under X, dropping in Exult's SDL2 window puts the asset right at the spot you dropped at.
On macOS with native Exult and Quartz GTK+2 this doesn't work, the location of the drop is where the mouse was last tracked before you left the window (usually one of the edges, unless you tabbed out).
All we tried out pointed to the fact that the location update needs to be done by the dropfile event in SDL2, not by our own (which always only worked after the Exult window getting focus).

This patch adds this to SDL_cocoawindow.m and it works perfectly, passing the correct coordinates to our code (SDL_GetMouseState()).

* Use Clang/GCC builtins for SDL byteswapping functions

__builtin_bswap32/64 were introduced in GCC 4.3. __builtin_bswap16 was
not available on x86 until GCC 4.8 due to a bug.

__builtin_bswap32/64 were introduced in Clang 2.6. __builtin_bswap16
was introduced in Clang 3.2.

* Disabled Bluetooth if BLE is not supported
BluetoothManager is supported for Android API 18+. On older versions, skip
Bluetooth instead of crashing.

* [KMS/DRM] Prevent creating another default cursor everytime a window is created. Other fixes and cleanups.

* [KMS/DRM] Fix cpmpilation warnings. Thanks to Ozkan Sezer for pointing this out!

* [KMS/DRM] Small readability changes.

* Fixed joysticks generating SDL mouse events

* [KMS/DRM] Go back to the LEGACY interface only because using planes breaks compatibility with HW, so no advantage on using ATOMIC.

* Fixed Xbox One Series X share button incorrectly triggering on newer firmware

* Fixed bug 5080 - SDL_netbsdaudio: Always use the device's preferred frequency

Nia Alarie

The NetBSD kernel's audio resampling code is much simpler and lower quality than libsamplerate.

Presumably, if SDL always performs I/O on the audio device in its native frequency, we can avoid resampling audio in the kernel and let SDL do it with libsamplerate instead.

* regenerated configure

* fixed permissions of xcode project file

* KMSDRM_LEGACY is no longer legacy

* [KMS/DRM] Fix vkQuake3 in OpenGL mode.

* acinclude/libtool.m4: Apply macos11 patch from libtool bug #44605

https://debbugs.gnu.org/cgi/bugreport.cgi?bug=44605
https://github.com/macports/macports-ports/blob/master/devel/libtool/files/dynamic_lookup-11.patch
( Also see https://debbugs.gnu.org/cgi/bugreport.cgi?bug=44684 )

This also implicitly covers the macos10.10+ support patch from libtool
mainstream which has been in since libtool-v2.4.3, i.e.:
http://git.savannah.gnu.org/gitweb/?p=libtool.git;a=commit;h=e145288b059e14ab7e58fc6a304e82d9dad282a6

* [KMS/DRM] Cleanup remainings from plane/scaling usage.

* SDL_UpdateNVTexture: for D3D11, same notation as SDL_UpdateTexture (bug libsdl-org#5430)

* Fixed bug 5465 - Invalid memcpy inside SDL_GestureDelTouch (Thanks dmikushin and Yuki Okumura)

* SDL_UpdateNVTexture: fixed pitch/bpp for GLES2 (bug libsdl-org#5430)

* [KMS/DRM] Fix fullscreen to windowed transition. Fix aspect ratio correction without using planes.

* [KMS/DRM] Move surface size info to window driverdata, for coherency.

* [KMS/DRM] Unused code cleaning.

* Gyro and Accel sensor support for Switch Pro Controller.
Note that axes are changed to match the axes we're using with PlayStation controllers, since users will appreciate consistent behaviour across devices.

* [KMS/DRM] Don't ask SDL to scale image when in Vulkan mode.

* [KMS/DRM] Refactor KMSDR_CreateSurface to group all non-Vulkan stuff in a block.

* opengl: More work on making line drawing match software renderer.

* [KMS/DRM] Add warning comentary to avoid future experiments with scaling.

* [KMS/DRM] Enable async pageflips.

* testgamecontroller: log which controller the event came from

* Only select the gamepad interfaces on the Xbox 360 wireless adapter

* Don't blink the Xbox 360 LED when setting the player slot, it's probably already been set by a driver

* [KMS/DRM] Refactor, improve and re-comment async pageflips code.

* [KMS/DRM] Remove unused header.

* [KMS/DRM] Adjust come return values. Improve comments.

* Fixed bug 5461 - Add rewritten WSCONS driver for OpenBSD

wahil1976

This patch adds a written-from-scratch WSCONS driver for OpenBSD. It does not have hardcoded keymaps, and it features mouse support when wsmux is available.

For this to work, it needs access to the /dev/wskbd* devices which are not available to non-root users by default. Access to those can be granted by changing /etc/fbtab to give the logging user the ownership of those devices.

* Fixed bug 5462 - debug trap update/fix of assembly for Apple devices

David Carlier

updating preprocessor constant and proposing 32 bits variant.

* Fixed bug 5451 - Can't create EGLSurface in Wayland from SDLWindow (no EGLNativeWindow pointer)

sashikknox

In some cases, need create EGLWindow with SDLWindow. In X11 i can get pointer to NativeWindow from **struct SDL_SysWMinfo wmInfo**
```C++
struct SDL_SysWMinfo wmInfo;
SDL_GetWindowWMInfo(ptSDLWindow, &wmInfo)
#if defined(__unix__) && defined(SDL_VIDEO_DRIVER_X11)
nativeWindow=(EGLNativeWindowType)wmInfo.info.x11.window;
nativeDisplay=(EGLNativeDisplayType)wmInfo.info.x11.display;
#endif
```
than i can create EGLSurface
```
eglCreateWindowSurface(nativeDisplay, EGL_CONFIG, nativeWindow, SURFACE_ATTRIBUTES);
```
in Wayland i can do it with same way, just need pointer to **EGLWindow**, we already have pointer to **wl_display** from **SDL_sysWMInfo**, need add to **wl** struct in SDL_SysWMInfo another pointer to **struct wl_egl_window *egl_window;**. And in wayland backend, in function **Wayland_GetWindowWMInfo** return pointer to **egl_window** from **SDL_WindowData**
Now i use patched statically built SDL2 in port of Quake 2 GLES2 for SailfishOS (it use QtWayland):
link to SDL2 commit and changed string for patch:
- savegame/sailfish-quake2@6858a61
- https://github.com/savegame/lp-public/blob/b1e29e87b9d15780e47f04918b329ac15554fc69/SDL2/src/video/wayland/SDL_waylandwindow.c#L463

link to use in Quake2 port:
1. here i get pointer to EGLNativeWindowType:  https://github.com/savegame/lp-public/blob/6d94fedb1b720da24999ae6286a1809cd3d55ff5/Engine/Sources/Compatibility/OpenGLES/EGLWrapper.c#L319
2. then use it for create EGLSurface: https://github.com/savegame/lp-public/blob/6d94fedb1b720da24999ae6286a1809cd3d55ff5/Engine/Sources/Compatibility/OpenGLES/EGLWrapper.c#L391

* Fixed bug 5463 - generated Wayland interfaces are included in the library's ABI

Simon McVittie

In versions since 1.15, the `code` mode is a deprecated alias for
`public-code`, which emits symbols with default visibility, overriding
SDL's -fvisibility=hidden option.

Use the `private-code` mode instead. This emits symbols with hidden
visibility, so they do not affect the ABI of libSDL.

See also: https://bugreports.qt.io/browse/QTBUG-73099,
https://lists.freedesktop.org/archives/wayland-devel/2018-February/037097.html

* Fixed bug 5287 - Support building for UWP with CMake

Jan Niklas Hasse

Actually the SDL2-static target works, if I set SDL_SENSOR to OFF. Awesome!

See this patch: https://github.com/microsoft/vcpkg/blob/master/ports/sdl2/0003-sdl2-fix-uwp-build.patch

* Fixed bug 5195 - Replugging in “mixed” controller types crashes on macOS

RustyM

This is related to Bug 5034, but crashes under a somewhat different condition.

In the latest tip (changeset 13914) or with the SDL 2.0.12 source + David’s 5034 patch, unplugging and then replugging in certain controller types on macOS will crash. A mix of new controllers like Switch Pro, PS4 and Xbox One all work without issue. But if a controller without a rumble function, like many SNES retro USB gamepads, is mixed with a PS4 or Switch Pro controller it will crash.

File: joystick/darwin/SDL_sysjoystick.c
Function: static recDevice *FreeDevice(recDevice *removeDevice)
On line 159: while (device->pNext != removeDevice) {
Causes: Thread 1: EXC_BAD_ACCESS (code=1, address=0x188)

This can be reproduced in testgamecontroller" by starting the test program with both a “retro” controller plugged in and a “modern rumble” controller (Switch Pro/PS4). This may crash on launch, but it depends on which controller ends up as device 0. If it doesn’t crash, unplug the “modern rumble” controller and plug it back in.

Some of the "retro" controllers I’ve seen this crash with:
- iBuffalo SNES Controller
- 8Bitdo SN30 Gamepad (in MacOS mode)
- Retrolink NES Controller
- HuiJia SNES Controller Adaptor

The issue appears macOS specific. Seen on 10.12.6 and 10.14.6. Not seen on Windows 10.

The while loop in FreeDevice() assumes that every device is not NULL.

    recDevice *device = gpDeviceList;
    while (device->pNext != removeDevice) {
        device = device->pNext;
    }
    device->pNext = pDeviceNext;

So maybe we should check for NULL here? Or instead prevent adding NULL devices to the list in the first place? Checking device for NULL before entering the loop appears to work.

    recDevice *device = gpDeviceList;
    if (!device) {
        while (device->pNext != removeDevice) {
            device = device->pNext;
        }
    }
    device->pNext = pDeviceNext;

* Fixed bug 5445 - Incorrect Switch Pro Controller face buttons when SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS disabled

jibb

I'm testing with DualShock 4, DualSense, Switch Pro Controller, and PowerA Switch Controller.

I'm using the standard mapping file from here:
https://raw.github.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt

With SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS turned off (set to "0") I expect the button positions to be the same on all devices, based on Xbox controller button naming (eg SDL_GameControllerGetButton(g, SDL_CONTROLLER_BUTTON_Y) gives me whether the North face button is pressed).

However, the Switch Pro Controller layout is wrong (matching labels rather than positions, so X and Y are swapped and A and B are swapped). And with the PowerA controller the East and West buttons are correct, but the North and South buttons are swapped instead.

Mathias Kaerlev

Also seeing this on 2.0.14. This is most likely a regression, since we weren't seeing this on an earlier SDL version.

I suspect it might be caused by this commit:
spurious/SDL-mirror@a569b21#diff-da9344d94c66b8c702a45e7649f412039f08bba83bd82de33f5c80ea9c8c39d5

It seems like both the HIDAPI driver and SDL_gamecontroller.c will try to swap the buttons if the hint is set to 0, causing the button remap to cancel out.

* Make sure the HIDAPI device is locked when closing it, in case there is rumble pending that didn't complete

* Always lock the HIDAPI device when closing, in case rumble is pending

* Added HIDAPI rumble debug info

* Fixed rumble reset failing for Switch Pro controllers in USB mode

* Phantom Nintendo Switch Pro Controller initialization problem

* Get the serial number for the Nintendo Switch Pro controller

* Fixed build

* SDL_hidapi_switch.c: fix build with older compilers

* [KMS/DRM] Small fix to KMSDRM_Waitpageflip(). More comments on how it works.

* Fixed the screenshot button mapping on third party Bluetooth Nintendo Switch Pro controllers

* fix build with --disable-directx

* Fixed bug 5473 - Add WSCONS support for NetBSD

wahil1976

This patch adds WSCONS support for NetBSD.

* [KMS/DRM] Fix for bug libsdl-org#5470: ratio correction for fullscreen windows with no matching resolution. Correct bracket position in else statements so they follow the coding style.

* [KMS/DRM] Fix for bug libsdl-org#5468: corruption on dynamic cursor changing caused by wrong buffer size.

* Add basic testgles2_sdf program to demonstrate sign distance field with opengles2

* Fix declarations after statement

* fix AC_CHECK_HEADER for libusb.h

* hidapi/libusb/hid.c: whitespace tidy-up.

* SDL_virtualjoystick.c: remove wrong #endif comment.

* [KMS/DRM] Revert unaproved fix for bug libsdl-org#5465.

* hidapi/libusb/hid.c: fix race condition on device close (bug libsdl-org#5484)

From hidapi mainstream git: libusb/hidapi#142
libusb/hidapi@d2c3a98

Read callback may fire itself on its own even after its been requested
to stop and exactly before the calling code waits for its completion in
indefinite loop.  Explicitly preventing re-fireing the submission loop
fixes the issue.

* Use PS4 rumble hint as the default for the PS5 rumble hint

Existing SDL applications may not know about the need to set a specific
hint to enable rumble on PS5 controllers, even though they may already
set the equivalent SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE hint for PS4
controller rumble support.

Rather than requiring those developers update their apps, let's use the
SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE value as an indication of the behavior
they are expected for all PlayStation controllers.

* Implement keyboard grab support for Wayland

Use zwp_keyboard_shortcuts_inhibit_manager_v1 to allow SDL applications
to capture system keyboard shortcuts like Alt+Tab when keyboard grab is
enabled via SDL_HINT_GRAB_KEYBOARD.

* Don't add paddle mappings for the Xbox One Elite Series 1 controller, since they can't be unmapped and read directly on that controller.

* Hint SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS added so we can recognise a Joy-Con as half a Pro Controller, so we can read its analog input and read its sensors just like we do a Pro Controller.

* renamed my_gradd.h to SDL_gradd.h

* Implement support for minimizing windows on Wayland

This required a bit of extra code to deal with the transition from minimized
back to fullscreen

* Fixed initializing the Nyko and EVORETRO GameCube adaptors

This requires root on most Linux distributions, as we have to directly send USB messages to the devices to enable input reports.

* Make sure we only do GameCube adapter initialization if we were able to load libusb

* Improve reliability of cursor hiding on GNOME Wayland

Hiding the cursor doesn't appear to work reliably on GNOME when another window
steals mouse focus right as we call SDL_ShowCursor(SDL_DISABLE). This can happen
when the keyboard shortcut inhibition permission prompt appears in response to a
call to SDL_SetRelativeMouseMode() with SDL_HINT_GRAB_KEYBOARD=1. The result is
that the default cursor is stuck locked in position and visible on screen
indefinitely.

By redrawing the cursor on pointer focus enter, the cursor now disappears upon
the first mouse motion event. It's not perfect but it's way better than the
current behavior.

* Fixed build on Android and iOS

* Fixed build

* hidapi.h: adjust so that it gives a smaller diff against mainstream

* old os2 analogue joystick code ported from SDL-1.2. disabled by default,

build-tested only.

* SDL_dinputjoystick.c: fixes to dfDIJoystick2[] array from Wine git.

Fix V/A/FSlider dwOfs values in c_dfDIJoystick2
https://source.winehq.org/git/wine.git/commitdiff/af2f4194263702a946c65d255580176ee50b5914

Add missing ASPECT flags for c_dfDIJoystick2
https://source.winehq.org/git/wine.git/commitdiff/e2e100272ffede3c720da7bbd11b53ac0bcee8eb

Closes bug libsdl-org#5474.

* ControllerList: fix typo

* Added support for the EVORETRO GameCube Adapter in PC mode

* fix permissions of config.guess and config.sub

* minor autotools build system updates.

* Implement support for inhibiting the screensaver on Wayland

We support both the org.freedesktop.ScreenSaver D-Bus API (same as the X11
backend) and the Wayland idle_inhibit_unstable_v1 protocol.

Some Wayland compositors only support one or the other, so we need both to
for broad compatibility.

* Fix continuous scrolling speed on Wayland

Wayland compositors seem to have standardized on 10 units per "wheel tick" for
continuous scroll events, so we need to convert these axis values to ticks by
dividing by 10 before reporting them in SDL_MOUSEWHEEL events.

* added SDL_JOYSTICK_OS2 to SDL_config.h.in and SDL_config.h.cmake

* renamed SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H to SDL_HAVE_MACHINE_JOYSTICK_H

* os2audio: changed backend name from MMOS2 to DART (like SDL-1.2)

* move outdated winmm and psp joystick codes to struct _SDL_JoystickDriver

build-tested only. (bug libsdl-org#5472.)

* Implement keyboard grab support for Windows

This is implemented via a low-level keyboard hook. Unfortunately, this is
rather invasive, but it's how Microsoft recommends that it be done [0].
We want to do as little as possible in the hook, so we only intercept a few
crucial modifier keys there, while leaving other keys to the normal event
processing flow.

We will only install this hook if SDL_HINT_GRAB_KEYBOARD=1, which is not
the default. This will reduce any compatibility concerns to just the SDL
applications that explicitly ask for this behavior.

We also remove the hook when the grab is terminated to ensure that we're
not unnecessarily staying involved in key event processing when it's not
required anymore.

[0]: https://docs.microsoft.com/en-us/windows/win32/dxtecharts/disabling-shortcut-keys-in-games

* Fixed bug 5467 - SDL sys timer Mac OS update proposal

David Carlier

Change of api from 2016 which reduce code complexity a bit.

* Fixed bug 5466 - Add haptic support for Stadia Controller

Dimitriy Ryazantcev

Consider adding support for Stadia Controller haptics.

Here is example code how to deal with it:
https://github.com/chromium/chromium/blob/99314be8152e688bafbbf9a615536bdbb289ea87/device/gamepad/hid_haptic_gamepad.cc#L45

* Minor cleanup

* waylandtouch: Don't export interface structs
These are explicitly written in C code rather than generated at build
time, so they weren't affected by changing how we invoke
wayland-scanner.

Signed-off-by: Simon McVittie <smcv@collabora.com>

* Added Stadia controller source file to Visual Studio and Xcode projects

* Implement Wayland_SetWindowResizable

* [KMS/DRM] Bugfix for libsdl-org#5489: Non-FULLSCREEN windows incorrecty use videomode changing to look fullscreen.

* fix build failure due to -Werror=declaration-after-statement (bug libsdl-org#5500)

* minor clean-up in SDL_os2audio.c

* CMakeLists.txt: fix check_symbol_exists() for clock_gettime_nsec_np

* better check for clock_gettime_nsec_np() -- cf. bug libsdl-org#5467.

* GLES2 SDL_Renderer: remove old ZUNE_HD defines and simplify shader cache

* Refactor keyboard grab to be managed by the video core

This gives us flexibility to add others hints to control keyboard grab behavior
without having to touch all of the backends. It also allows us to possibly
expose keyboard grab separately from mouse grab for applications that want to
manage those independently.

* Fix grabbing Alt+Tab and Alt+Esc on Windows 7

* wayland: cancel key repeat when keyboard focus is lost

SDL_SetKeyboardFocus(NULL) will lift any keys still pressed when keyboard focus
leaves the window, but then key repeat comes behind our backs and presses the
key down again. This results in an infinite stream of SDL_KEYDOWN events when
focus leaves the window with a key down (particularly noticeable with Alt+Tab).

* Rename SetWindowGrab() to SetWindowMouseGrab()

* Removed non-functional window grab implementations

* Fixed bug 5493 - Hint to let the user opt out of having Switch controllers' Home button lit when opened

jibb

New hint to let the user opt out of having Switch controllers' Home button lit when opened.

This is more consistent with the Switch itself (which doesn't light the button normally) and may be preferred by users who may disconnect their controller without letting the application close it.

I think this warrants a Switch-specific hint because the default behaviour is unusual (inconsistent with using a Switch controller on a Switch itself or with some other programs on PC), and because of that it's distinct from other lights (the player number on Switch controllers and the player colour on PlayStation controllers).

* Fixed bug 5481 - iOS-specific main sources not used for CMake build.

Aaron Barany

The CMake build for SDL doesn't set SDLMAIN_SOURCES on iOS to the sources in src/main/ios. As a result, SDL fails to initialize since it falls back to the dummy main. Adding the line file(GLOB SDLMAIN_SOURCES ${SDL2_SOURCE_DIR}/src/main/uikit/*.c) fixes the issue.

* Fixed bug 5497 - SDL_COMPOSE_ERROR is wrong

UMU

#define SDL_COMPOSE_ERROR(str) SDL_STRINGIFY_ARG(__FUNCTION__) ", " str

I think SDL_STRINGIFY_ARG should be removed.

#define SDL_COMPOSE_ERROR(str) __FUNCTION__ ", " str

(verified with Visual Studio 2019)

* DirectFB: Split input grab handling into keyboard and mouse parts

The grabbed_window field is superfluous now since SDL added the
SDL_GetGrabbedWindow() function, so it can be removed.

DirectFB_SetWindowMouseGrab() is also simplified because SDL handles ungrabbing
any previously grabbed window prior to calling SetWindowMouseGrab() now.

Compile-tested only.

* SDL_SoftStretch: re-enable USE_ASM_STRETCH path for gcc >= 4.6

* Expose separate keyboard and mouse grab support

This adds SDL_SetWindowKeyboardGrab(), SDL_GetWindowKeyboardGrab(),
SDL_SetWindowMouseGrab(), SDL_GetWindowMouseGrab(), and new
SDL_WINDOW_KEYBOARD_GRABBED flag. It also updates the test harness to exercise
this functionality and makes a minor fix to X11 that I missed in
https://hg.libsdl.org/SDL/rev/02a2d609369b

To fit in with this new support, SDL_WINDOW_INPUT_CAPTURE has been renamed to
SDL_WINDOW_MOUSE_CAPTURE with the old name remaining as an alias for backwards
compatibility with older code.

* SDL_SoftStretch: disable asm path if mprotect isn't available (see bug libsdl-org#3816)

* SDL_UpdateTexture: intersect update rect with texture dimension
- fix crash with software renderer
- fix non texture update with opengl/gles2

* SDL_Update{YUV,NV}Texture: also intersect rect with texture dimension

* Fixed building with mingw64

* Fixed bug 3816 - asm code in video/SDL_stretch.c

Ozkan Sezer

- adds MSVC __declspec(align(x)) support,
- disables asm if PAGE_ALIGNED no macro is defined,
- still disables asm for gcc < 4.6, need more info,
- drops Watcom support.

* The Sharkoon Skiller SGH2 headset hangs in DirectInput enumeration, so avoid it here just in case.

See bug 5485 for details.

* Fixed compile warning

* Added explicit case from Uint8 to int before subtracting offset

* Fixed bug 3816 - asm code in video/SDL_stretch.c

Sylvain

I propose this new version for SDL_stretch.c that drops mprotect and asm

Code is similar to the StretchLinear, but the steps computation are kept similar to the nearest.
so that:
- it's pixel perfect with nearest
- as fast as asm I think
- no asm, nor mprotect
- benefit for all archicture

* SDL_LowerSoftStretchLinear: assign result from scale_mat() to ret.

otherwise it would always return -1 when SSE and NEON instrinsics
are absent.

* X11: Ungrab the keyboard when the mouse leaves the window

GNOME Mutter requires keyboard grab for certain important functionality like
window resizing, interaction with the application context menu, and opening the
Activites view. To allow Mutter to grab the keyboard as needed, we'll ungrab
when the mouse leaves our window.

To be safe, we'll do this for all WMs since forks of Mutter and Matacity (and
possibly others) may have the same behavior, and we don't want to have to keep
track of those.

* Added WIN_IsWindows8OrGreater() for internal use

* Fixed PS4 controllers over Bluetooth on Windows 7

* Fixed build warning

* Fixed compiler warnings

* SDL_stretch: remove un-used vars, same notation as blit functions

* Fixed bug 5510 - simplify the scaling functions

* Fixed bug 5510 - simplify the scaling functions blit auto (generated file)

* config.guess and config.sub updates from mainstream

* SDL_config_os2.h: remove some duplicated lines.

* Note that the Logitech G29 (PS4) is a racing wheel

* Make sure we don't create a game controller mapping for HID devices that aren't supported by HIDAPI

* Add checks for maximun scaling size (see bug libsdl-org#5510)

* Remove old YUV fixme

* Properly handle keys already down when the hook is installed

For keys that are already down when we install the keyboard hook, we need to
allow the WM_KEYUP/WM_SYSKEYUP message to be processed normally. This ensures
that other applications see the key up, which prevents the key from being stuck
down from the perspective of other apps when our grab is released.

* [KMS/DRM] Patch for bug libsdl-org#5513. KMSDRM backend can now manage and use several displays.

* [KMS/DRM] Remove unused KMSDRM_SetWindowGrab prototype in header file.

* Remove checks on destination scaling size (see bug libsdl-org#5510)

* added --enable-xinput switch for windows builds

* Fixed crash if the GameCube controller hasn't been opened yet

* [KMS/DRM] Correct small omission on bugfix libsdl-org#5513: y-coord correction has to be done on WarpMouseGlobal, too.

* Revert checks on destination scaling size (see bug libsdl-org#5510)

* Add default handler for Alt+Tab while keyboard grab is enabled

By default, we will minimize the window when we receive Alt+Tab with a
full-screen keyboard grabbed window to allow the user to escape the
full-screen application.

Some applications like remote desktop clients may want to handle Alt+Tab
themselves, so provide an opt-out via SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED=0.

* [KMS/DRM] Fix for bug libsdl-org#5518: only do async pageflips when hardware supports them.

* [KMS/DRM] Merge patch for bug 5522#: Implement KMSDRM_GetWindowWMInfo().

* wayland: Fix transform and scale handling when setting display mode

* cmake: enable AddressSanitizer in Debug builds

* free the 'data_device_manager'

* free 'outputs' in 'Wayland_DestroyWindow'

* Don't enable address sanitize flags without checking compiler first

* Fixed bug 5524 - Pass NSString to NSLog()

Hiroyuki Iwatsuki

If you pass the C string directly to NSLog(), it will be garbled with Japanese and probably other language strings, or no log will be output at all.

NSLog("Hello, World!"); // => "Hello, World!"
NSLog("こんにちは、世界!"); // => No output...

Therefore, you need to convert the string to an NSString before passing it to NSLog().

NSString *str = [NSString stringWithUTF8String:"こんにちは、世界!"];
NSLog(@"%@", str); // => "こんにちは、世界!"

Thank you.

* wayland: Don't crash when the properties of already existing wl_output change

* Don't uncorrelate while rumble is active and stay correlated longer in case raw input messages are lagging a bit.

* cmake: enable AddressSanitizer in Debug builds if supported

* Removed support for clock_gettime_nsec_np()

SDL_GetTicks() was broken and it's not adding any real value here.

* Added test command line options to force different window types

* Fixed bug 5471 - Creating a fullscreen desktop window goes windowed temporarily

This is caused by the Metal renderer recreating the window because by default we create an OpenGL window on macOS.

It turns out that at least on macOS 10.15, a window that has been initialized for OpenGL can also be used with Metal. So we'll skip recreating the window in that case.

* Fixed detecting the paddles on the Xbox Elite Series 1 controller

* SDL_ConvertColorkeyToAlpha: remove and clarify a FIXME
This function doesn't handle bpp 1 or 3 case, because those formats never have an alpha channel

* SDL_vulkan_utils: minor code clean-up

* KMSDRM doesn't have a window manager, so all windows are fullscreen

* Android: documention update

* Backed out changeset 1cde3dd0f44d - this breaks windows which are created and then set to FULLSCREEN_DESKTOP

* Fixed compiler warning

* Updated runtime dependency on libudev

* Fix Xbox Series X controller on macOS

There were two different implementations of IsBluetoothXboxOneController(), one
in SDL_hidapi_xbox360.c and one in SDL_hidapi_xboxone.c. The latter had been
updated to include USB_PRODUCT_XBOX_ONE_SERIES_X_BLUETOOTH while the former had
not.

This mismatch led to the Xbox Series X failing on macOS only. We have special
code for handling the 360Controller driver for macOS which requires us to use
the Xbox 360 driver for wired Xbox One controllers, and the SDL_hidapi_xbox360
version of IsBluetoothXboxOneController() was used to determine which devices
were wired.

In addition to adding the missing USB_PRODUCT_XBOX_ONE_SERIES_X_BLUETOOTH, this
change moves IsBluetoothXboxOneController() into a single shared function which
will ensure this bug won't happen again.

* [KMS/DRM] Restore all-windows-are-fullscreen functionality, since there is no window manager in KMSDRM.

* [KMS/DRM] Remove redundant SDL_SendWindowEvent() call.

* [KMS/DRM] Merge patch for bug libsdl-org#5532: No need to correct cursor position now that all windows are fullscreen. Link: https://bugzilla.libsdl.org/show_bug.cgi?id=5519.

* [KMS/DRM] Replace indent tabs with spaces, as intended.

* [KMS/DRM] Fix build warning.

* minor updates to libc function checks

* SDL: fix packet handling for original version of Stadia FW

* avoid some pedantic warnings in array initializers

* add '-shared-libasan' to debug flags (bug libsdl-org#5533)

* enable AddressSanitizer only for GCC 5 onwards (bug libsdl-org#5533)

* make AddressSanitizer optional and disabled by default

* [KMS/DRM] Bugfix number libsdl-org#5535: Improve reliability, by wahil1976.

* free the 'display' after it was added to global list

* Backed out changeset 852a7bdbdf4b
This causes a use-after-free memory error

* Fix waiting on condition variables with the SRW lock implmentation

When SleepConditionVariableSRW() releases the SRW lock internally, it causes
our SDL_mutex_srw state to become inconsistent. The lock is unowned yet inside,
the owner is still the sleeping thread and more importantly the owner count is
still 1.

The next time someone acquires the lock, they will bump the owner count from 1
to 2. At that point, the lock is hosed. From the internal lock state, it looks
to us like that owner has acquired the lock recursively, even though they have
not. When they call SDL_UnlockMutex(), it will see the owner count > 0 and not
call ReleaseSRWLockExclusive().

Now when someone calls SDL_CondSignal(), SleepConditionVariableSRW() will start
the wakeup process by attempting to re-acquire the SRW lock. This will deadlock
because the lock was never released after the other thread had used it. The
thread waiting on the condition variable will never be able to wake up, even if
the SDL_CondWaitTimeout() function is used and the timeout expires.

* Fixed bug 5543 - Wayland: Fix waylandvideo.h warnings

wahil1976

This patch fixes the warnings seen when compiling the Wayland backend. This will also be required in the future to avoid issues with compilation.

* Fixed bug 5539 - Clang 11 fails to compile a CMake build with conflicting types for _m_prefetchw

vladius

In SDL_cpuinfo.h it seems like <intrin.h> is not included when __clang__ is defined, as the comment in the file explicitly reads:
"Many of the intrinsics SDL uses are not implemented by clang with Visual Studio"

However, the SDL_endian.h header does include <intrin.h> without any precautions like:
>#ifdef _MSC_VER
>#include <intrin.h>
>#endif


Maybe it should be changed to something like:
>#ifdef _MSC_VER
>#ifndef __clang__
>#include <intrin.h>
>#endif
>#endif

* Report found joysticks to SDL for event generation (fixes testjoystick)

* Update for 2.0.14 release

* Do not loop forever

* Update version string

* Try to filter out invalid UTF-8 bytes when sending text events (libsdl-org#190)

* Open screens with SA_LikeWorkbench. This should fix issue with requester palette

* Use smart refresh mode also in fullscreen mode. This avoids potential cosmetic issues with open requesters

* Give screen a title for identification purposes

* Implement SDL_OpenURL

* Adapt to SDL_VideoDevice struct changes

* Wait for window resize to happen to avoid issue where consequtive SetWindowAttrs calls seem to fail in SDL_SetWindowSize + SDL_SetWindowPos combo

* Work around GCC10 change that triggered linking failure with static library

* Disable SA_Compositing in fullscreen mode for a small performance gain

* Set global IExec and INewlib only if required

* Cleanup

* More cleanup

* More cleanup

* Cleanup

* Patch OGLES2 renderer compilation for AmigaOS 4

Co-authored-by: Cameron Gutman <aicommander@gmail.com>
Co-authored-by: Sam Lantinga <slouken@libsdl.org>
Co-authored-by: Ozkan Sezer <sezeroz@gmail.com>
Co-authored-by: Sylvain Becker <sylvain.becker@gmail.com>
Co-authored-by: Manuel Alfayate Corchete <redwindwanderer@gmail.com>
Co-authored-by: Jordan Christiansen <xordspar0@gmail.com>
Co-authored-by: JibbSmart <none@none>
Co-authored-by: Ryan C. Gordon <icculus@icculus.org>
Co-authored-by: Cameron Gutman <cameron.gutman@gmail.com>
Co-authored-by: Simon McVittie <smcv@collabora.com>
Co-authored-by: Ethan Lee <flibitijibibo@flibitijibibo.com>
Co-authored-by: Brandon DeRosier <x@bdero.me>
Co-authored-by: Sebastian Krzyszkowiak <sebastian.krzyszkowiak@puri.sm>
Co-authored-by: Christian Rauch <Rauch.Christian@gmx.de>
Co-authored-by: capehill <juha.niemimaki@gmail.com>
@moocow1452
Copy link

Is this draft still viable, or would it be better at this point to start from scratch?

@icculus
Copy link
Collaborator

icculus commented Apr 21, 2024

This was for SDL2, before SDL2 moved off to a branch. The main branch is SDL3 now, which is why there are massive merge conflicts.

My suspicion is that this PR will work against the SDL2 branch just fine, but I don't think GitHub lets us retarget a PR to a different branch, short of just generating a new PR. I might take a run at doing this if I get a moment, if Eric doesn't want to, because I think this is a fun thing to have in SDL.

@madebr madebr changed the base branch from main to SDL2 April 21, 2024 13:40
@madebr
Copy link
Contributor

madebr commented Apr 21, 2024

My suspicion is that this PR will work against the SDL2 branch just fine, but I don't think GitHub lets us retarget a PR to a different branch, short of just generating a new PR. I might take a run at doing this if I get a moment, if Eric doesn't want to, because I think this is a fun thing to have in SDL.

The GitHub UI lets you change the target branch (just below the title).
I changed the target branch to SDL2.

@icculus
Copy link
Collaborator

icculus commented Apr 21, 2024

The GitHub UI lets you change the target branch (just below the title).

Ohhhh, it's hidden behind the "edit" button (which I thought only changed the title). Nice one!

I'll see about resolving the SDL2 conflicts, then. :)

@slouken
Copy link
Collaborator

slouken commented Apr 21, 2024

Should this be an SDL3 feature?

@icculus
Copy link
Collaborator

icculus commented Apr 21, 2024

Well I just force-pushed the resolved version to eric's clone instead of mine by accident (yikes!) but this seems to have not mangled the PR, so that's good. I still need to fix the build up.

@boozook
Copy link

boozook commented Apr 22, 2024

Thank you for this huge work! I hope to see it in the upstream soon. ❤️‍🔥
I'll just put it here. If you need some easy & fast solution to setup Playdate SDK on CI - here I am with our cross-platform neat action. I hope it can be helpful for you.

@moocow1452
Copy link

moocow1452 commented May 11, 2024

Using a fresh pull from Eric's branch with the custom Makefile specified in the previous comment, it seems to get part way through the compile, then chokes on an undeclared variable partway through SDL joystick.

user@user-reks:~/Projects/VVVVVV/third_party$ make
detected_OS is "Linux"
mkdir -p build
mkdir -p build/dep
mkdir -p `dirname build/SDL/src/joystick/playdate/SDL_sysjoystick.o`
/usr/bin/arm-none-eabi-gcc -g3 -c -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -D__FPU_USED=1 -O2 -falign-functions=16 -fomit-frame-pointer -gdwarf-2 -Wall -Wno-unused -Wstrict-prototypes -Wno-unknown-pragmas -fverbose-asm -Wdouble-promotion -mword-relocations -fno-common -ffunction-sections -fdata-sections -Wa,-ahlms=build/SDL_sysjoystick.lst -DTARGET_PLAYDATE=1 -DTARGET_EXTENSION=1  -MD -MP -MF build/dep/SDL_sysjoystick.o.d -I . -I . -I /home/user/Downloads/PlaydateSDK-2.4.2/C_API -I SDL/include SDL/src/joystick/playdate/SDL_sysjoystick.c -o build/SDL/src/joystick/playdate/SDL_sysjoystick.o
SDL/src/joystick/playdate/SDL_sysjoystick.c: In function 'PLAYDATE_JoystickUpdate':
SDL/src/joystick/playdate/SDL_sysjoystick.c:54:9: error: 'pd' undeclared (first use in this function)
   54 |         pd->system->getButtonState(&current, NULL, NULL);
      |         ^~
SDL/src/joystick/playdate/SDL_sysjoystick.c:54:9: note: each undeclared identifier is reported only once for each function it appears in
SDL/src/joystick/playdate/SDL_sysjoystick.c: At top level:
SDL/src/joystick/playdate/SDL_sysjoystick.c:198:5: warning: initialization of 'const char * (*)(int)' from incompatible pointer type 'int (*)(int)' [-Wincompatible-pointer-types]
  198 |     PLAYDATE_JoystickGetDevicePlayerIndex,
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDL/src/joystick/playdate/SDL_sysjoystick.c:198:5: note: (near initialization for 'SDL_PLAYDATE_JoystickDriver.GetDevicePath')
SDL/src/joystick/playdate/SDL_sysjoystick.c:199:5: warning: initialization of 'int (*)(int)' from incompatible pointer type 'void (*)(int,  int)' [-Wincompatible-pointer-types]
  199 |     PLAYDATE_JoystickSetDevicePlayerIndex,
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDL/src/joystick/playdate/SDL_sysjoystick.c:199:5: note: (near initialization for 'SDL_PLAYDATE_JoystickDriver.GetDeviceSteamVirtualGamepadSlot')
SDL/src/joystick/playdate/SDL_sysjoystick.c:200:5: warning: initialization of 'int (*)(int)' from incompatible pointer type 'SDL_JoystickGUID (*)(int)' {aka 'SDL_GUID (*)(int)'} [-Wincompatible-pointer-types]
  200 |     PLAYDATE_JoystickGetDeviceGUID,
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDL/src/joystick/playdate/SDL_sysjoystick.c:200:5: note: (near initialization for 'SDL_PLAYDATE_JoystickDriver.GetDevicePlayerIndex')
SDL/src/joystick/playdate/SDL_sysjoystick.c:201:5: warning: initialization of 'void (*)(int,  int)' from incompatible pointer type 'SDL_JoystickID (*)(int)' {aka 'long int (*)(int)'} [-Wincompatible-pointer-types]
  201 |     PLAYDATE_JoystickGetDeviceInstanceID,
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDL/src/joystick/playdate/SDL_sysjoystick.c:201:5: note: (near initialization for 'SDL_PLAYDATE_JoystickDriver.SetDevicePlayerIndex')
SDL/src/joystick/playdate/SDL_sysjoystick.c:202:5: warning: initialization of 'SDL_JoystickGUID (*)(int)' {aka 'SDL_GUID (*)(int)'} from incompatible pointer type 'int (*)(SDL_Joystick *, int)' {aka 'int (*)(struct _SDL_Joystick *, int)'} [-Wincompatible-pointer-types]
  202 |     PLAYDATE_JoystickOpen,
      |     ^~~~~~~~~~~~~~~~~~~~~
SDL/src/joystick/playdate/SDL_sysjoystick.c:202:5: note: (near initialization for 'SDL_PLAYDATE_JoystickDriver.GetDeviceGUID')
SDL/src/joystick/playdate/SDL_sysjoystick.c:203:5: warning: initialization of 'SDL_JoystickID (*)(int)' {aka 'long int (*)(int)'} from incompatible pointer type 'int (*)(SDL_Joystick *, Uint16,  Uint16)' {aka 'int (*)(struct _SDL_Joystick *, short unsigned int,  short unsigned int)'} [-Wincompatible-pointer-types]
  203 |     PLAYDATE_JoystickRumble,
      |     ^~~~~~~~~~~~~~~~~~~~~~~
SDL/src/joystick/playdate/SDL_sysjoystick.c:203:5: note: (near initialization for 'SDL_PLAYDATE_JoystickDriver.GetDeviceInstanceID')
SDL/src/joystick/playdate/SDL_sysjoystick.c:204:5: warning: initialization of 'int (*)(SDL_Joystick *, int)' {aka 'int (*)(struct _SDL_Joystick *, int)'} from incompatible pointer type 'int (*)(SDL_Joystick *, Uint16,  Uint16)' {aka 'int (*)(struct _SDL_Joystick *, short unsigned int,  short unsigned int)'} [-Wincompatible-pointer-types]
  204 |     PLAYDATE_JoystickRumbleTriggers,
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDL/src/joystick/playdate/SDL_sysjoystick.c:204:5: note: (near initialization for 'SDL_PLAYDATE_JoystickDriver.Open')
SDL/src/joystick/playdate/SDL_sysjoystick.c:205:5: warning: initialization of 'int (*)(SDL_Joystick *, Uint16,  Uint16)' {aka 'int (*)(struct _SDL_Joystick *, short unsigned int,  short unsigned int)'} from incompatible pointer type 'Uint32 (*)(SDL_Joystick *)' {aka 'long unsigned int (*)(struct _SDL_Joystick *)'} [-Wincompatible-pointer-types]
  205 |     PLAYDATE_JoystickGetCapabilities,
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDL/src/joystick/playdate/SDL_sysjoystick.c:205:5: note: (near initialization for 'SDL_PLAYDATE_JoystickDriver.Rumble')
SDL/src/joystick/playdate/SDL_sysjoystick.c:206:5: warning: initialization of 'int (*)(SDL_Joystick *, Uint16,  Uint16)' {aka 'int (*)(struct _SDL_Joystick *, short unsigned int,  short unsigned int)'} from incompatible pointer type 'int (*)(SDL_Joystick *, Uint8,  Uint8,  Uint8)' {aka 'int (*)(struct _SDL_Joystick *, unsigned char,  unsigned char,  unsigned char)'} [-Wincompatible-pointer-types]
  206 |     PLAYDATE_JoystickSetLED,
      |     ^~~~~~~~~~~~~~~~~~~~~~~
SDL/src/joystick/playdate/SDL_sysjoystick.c:206:5: note: (near initialization for 'SDL_PLAYDATE_JoystickDriver.RumbleTriggers')
SDL/src/joystick/playdate/SDL_sysjoystick.c:207:5: warning: initialization of 'Uint32 (*)(SDL_Joystick *)' {aka 'long unsigned int (*)(struct _SDL_Joystick *)'} from incompatible pointer type 'int (*)(SDL_Joystick *, const void *, int)' {aka 'int (*)(struct _SDL_Joystick *, const void *, int)'} [-Wincompatible-pointer-types]
  207 |     PLAYDATE_JoystickSendEffect,
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~
SDL/src/joystick/playdate/SDL_sysjoystick.c:207:5: note: (near initialization for 'SDL_PLAYDATE_JoystickDriver.GetCapabilities')
SDL/src/joystick/playdate/SDL_sysjoystick.c:208:5: warning: initialization of 'int (*)(SDL_Joystick *, Uint8,  Uint8,  Uint8)' {aka 'int (*)(struct _SDL_Joystick *, unsigned char,  unsigned char,  unsigned char)'} from incompatible pointer type 'int (*)(SDL_Joystick *, SDL_bool)' {aka 'int (*)(struct _SDL_Joystick *, SDL_bool)'} [-Wincompatible-pointer-types]
  208 |     PLAYDATE_JoystickSetSensorsEnabled,
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDL/src/joystick/playdate/SDL_sysjoystick.c:208:5: note: (near initialization for 'SDL_PLAYDATE_JoystickDriver.SetLED')
SDL/src/joystick/playdate/SDL_sysjoystick.c:209:5: warning: initialization of 'int (*)(SDL_Joystick *, const void *, int)' {aka 'int (*)(struct _SDL_Joystick *, const void *, int)'} from incompatible pointer type 'void (*)(SDL_Joystick *)' {aka 'void (*)(struct _SDL_Joystick *)'} [-Wincompatible-pointer-types]
  209 |     PLAYDATE_JoystickUpdate,
      |     ^~~~~~~~~~~~~~~~~~~~~~~
SDL/src/joystick/playdate/SDL_sysjoystick.c:209:5: note: (near initialization for 'SDL_PLAYDATE_JoystickDriver.SendEffect')
SDL/src/joystick/playdate/SDL_sysjoystick.c:210:5: warning: initialization of 'int (*)(SDL_Joystick *, SDL_bool)' {aka 'int (*)(struct _SDL_Joystick *, SDL_bool)'} from incompatible pointer type 'void (*)(SDL_Joystick *)' {aka 'void (*)(struct _SDL_Joystick *)'} [-Wincompatible-pointer-types]
  210 |     PLAYDATE_JoystickClose,
      |     ^~~~~~~~~~~~~~~~~~~~~~
SDL/src/joystick/playdate/SDL_sysjoystick.c:210:5: note: (near initialization for 'SDL_PLAYDATE_JoystickDriver.SetSensorsEnabled')
SDL/src/joystick/playdate/SDL_sysjoystick.c:211:5: warning: initialization of 'void (*)(SDL_Joystick *)' {aka 'void (*)(struct _SDL_Joystick *)'} from incompatible pointer type 'void (*)(void)' [-Wincompatible-pointer-types]
  211 |     PLAYDATE_JoystickQuit,
      |     ^~~~~~~~~~~~~~~~~~~~~
SDL/src/joystick/playdate/SDL_sysjoystick.c:211:5: note: (near initialization for 'SDL_PLAYDATE_JoystickDriver.Update')
SDL/src/joystick/playdate/SDL_sysjoystick.c:212:5: warning: initialization of 'void (*)(SDL_Joystick *)' {aka 'void (*)(struct _SDL_Joystick *)'} from incompatible pointer type 'SDL_bool (*)(int,  SDL_GamepadMapping *)' {aka 'SDL_bool (*)(int,  struct _SDL_GamepadMapping *)'} [-Wincompatible-pointer-types]
  212 |     PLAYDATE_JoystickGetGamepadMapping
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDL/src/joystick/playdate/SDL_sysjoystick.c:212:5: note: (near initialization for 'SDL_PLAYDATE_JoystickDriver.Close')
make: *** [/home/user/Downloads/PlaydateSDK-2.4.2/C_API/buildsupport/common.mk:149: build/SDL/src/joystick/playdate/SDL_sysjoystick.o] Error 1

Would this be that hacking around that would be required from earlier or is that makefile unnecessary to make playdate compatible libraries?

EDIT: Additionally, I attempted to compile traditionally via cmake using the argument -DCMAKE_TOOLCHAIN_FILE=<path_to_playdate_SDK>/C_API/buildsupport/arm.cmake from https://github.com/nstbayless/playdate-cpp

That gave me this error:

  *** ERROR: Threads are needed by many SDL subsystems and may not be                                                    
  disabled                                                                                                               
Call Stack (most recent call first):                                                                                     
  CMakeLists.txt:3051 (message_error)   

Which lead me to #6344, implying we would need a custom makefile or some tweaking in the setup to get going.

@moocow1452
Copy link

Figured out the pd issue, needed to add extern PlaydateAPI* pd to the required files and tie up loose ends for the temp makefile. It segmentation faults on trying to compile everything, but I don't have the original main.c that @ericlewis was using in his file, so that's expected. I made my own pull request on Eric's repo to track my progress here so I won't flood this pull with minor updates. Thanks for the help and I'll touch base once things look ship shape.

@slouken
Copy link
Collaborator

slouken commented Aug 6, 2024

This hasn't been updated in a while and we're cleaning house for SDL 3.0. Please feel free to reopen this if you'd like to clean it up and get it in!

@slouken slouken closed this Aug 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants