Handmade Penguin (SDL Port) Discussion

Handmade Penguin is a tutorial for porting Handmade Hero to Linux using the SDL library.

I thought this thread might be a good place for people to post any questions they have about it (or SDL/Linux development in general), as well as report bugs, comments, etc.

To start off, I'll announce Chapter 11: Making Graphics Portable. I had to write half of this one twice thanks to a wayward power outage, so there might be a few half-finished sentances or similar lying around. :/

— David
I think it's a great thing you are dooing.

Thumbs up!
Chapter 12: Platform-independent Sound Output is now out.

If no-one objects, I'll no longer be doing both the ring buffer and SDL_QueueAudio() versions of the source code in future, unless there's a particularly interesting reason to look at it. Speak up now if this upsets you!

— David
In chapter 6, should SDL_CONTROLLERDEVI[color=#ff0000]D[/color]EADDED be SDL_CONTROLLERDEVI[color=#ff0000]C[/color]EADDED? :)

I was starting a list of comments and typos. The only real-code typo I saw so far was this. There were a few missing letters in the text here and there - I'll send you a full list when I'm caught up to the main stream. :D

Edited by David Vereb on
Fixed, thanks!

I'm looking forward to your comments: these were all written pretty quickly, so I'm sure there are lots of mistakes.

— David
Not sure if I should make new thread with this, but I am having issue with playing sound. It seems that no sound is playing out of my speakers.

This is my callback. This callback is being called by SDL, so I am not forgetting an SDL_PauseAudio(0) or anything like that.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
static void SDLAudioCallBack(void* userData, uint8_t* stream, int len) {
    int16_t* currSample = (int16_t*)stream;
    uint32_t tone = 256;
    uint32_t period = 48000 / tone;
    uint32_t halfPeriod = period / 2;

    for (size_t i = 0; i < (len / sizeof(*currSample)); i+=2) {
        
        int16_t halfSample = ((i / halfPeriod) % 2) ? 1 : -1;
        
        currSample[i] = halfSample * 3000; //left channel 
        currSample[i+1] = halfSample * 3000; //right channel
    }

}


This is my audio spec

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 SDL_AudioSpec desiredAudio = {};
    desiredAudio.channels = 2;
    desiredAudio.samples = 4096;
    desiredAudio.freq = SOUND_FREQ;
    desiredAudio.format = AUDIO_S16LSB;
    desiredAudio.callback = SDLAudioCallBack;

    if (SDL_OpenAudio(&desiredAudio, NULL) < 0) {
        printSDLErrorAndExit();
    }



Any help would be greatly appreciated! Thanks!


Also, in addition, it seems that _rdtsc() or __rdtsc() does not seem to be in x86intrin.h on Mac or Linux Mint for whatever reason (perhaps I am compiling with the wrong flags? I am compiling in C using clang, not g++. Maybe it's not in clang's std library?). As a workaround, I found that this implimentation seems to work:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
static inline uint64_t
__rdtsc(void)
{
	uint32_t eax = 0, edx;

	__asm__ __volatile__("cpuid;"
			     "rdtsc;"
				: "+a" (eax), "=d" (edx)
				:
				: "%rcx", "%rbx", "memory");

	__asm__ __volatile__("xorl %%eax, %%eax;"
			     "cpuid;"
				:
				:
				: "%rax", "%rbx", "%rcx", "%rdx", "memory");

	return (((uint64_t)edx << 32) | eax);
}


Just as a suggestion: If it turns out that these functions really are missing on these platforms and this implementation is good enough, would you want to update the tutorial with this implementation?

Thanks!

Edited by Dan on
I'm afraid I'm totally stumped: your sound code works perfectly here. The two follow-up questions I'd ask are:
  1. If you're using PulseAudio, does your game show up in the volume control?
  2. Does setting the environment variable SDL_AUDIODRIVER=alsa help? If you're using a non-default alsa device, you may also need AUDIODEV=<device>.

As to the intrinsics, it seems that clang only added support for _rdtsc in version 3.5, so you'll need to upgrade if you want to use the intrinsics. Otherwise, the inline assembly implementation will work fine. I've quickly noted this in the chapter, but I might discuss it further if I get time.

Best of luck,
— David
Chapter 13: Platform-indpendent User Input is out.

I've also upgraded the server it's hosted on, so if anything dies, do let me know.

— David
Found the issue. Thanks David! It seems that the correct audio device wasn't selected. I was confused because I was watching the Handmade hero archive before with no problems. Maybe for some reason, in Linux Mint, the correct audio device was assigned to firefox but not the rest of my programs or something.
Chapter 14: A Trip Down Memory Lane is now up.

The top-secret behind-the-scenes info:
  • The site now has a proper SSL certificate. Let me know if I broke the Apache config and you can no longer connect.
  • I spent far too long coming up with the title for this one, so I apologise for it being a bit later than usual.

— David
Chapter 15: Platform-indpendent Debug File I/O is up.

I've included a little bit on using the mmap() for mapping files into memory as a bonus!

— David
Sorry for the delay; Chapter 16 "Bits and Pieces" of Handmade Penguin is now up.

This is the longest chapter yet, and goes into the top secret techniques, passed down from Linux developer to Linux developer, for getting your binaries to work across lots of different distributions.

Please let me know if anything doesn't work, or doesn't make sense, or eats your pets and/or beloved family members. This sort of compatibility is made of hacks built on top of other, more horrible, hacks, so the result is always going to be a bit ugly.

Thanks, and apologies for the wait,
— David
Fear not, Chapter 17 is here.

With some luck, the delays that plagued the last couple of chapters are over. I have lots of notes on my notepad, so it's just typing up and debugging to go.

— David
It's Chapter 18 time for Handmade Penguin.

We look at getting refresh rates, sleeping with SDL_Delay() and synchronising to the vertical blank.

For the interested, here's a little bit of the raw data from one of my SDL_Delay() timing experiments. You can read more about how timers on linux work here.

Enjoy,
— David


SDL_Delay(1) takes 1.095611 ms
SDL_Delay(1) takes 1.079751 ms
SDL_Delay(1) takes 1.083415 ms
SDL_Delay(1) takes 1.085282 ms
SDL_Delay(1) takes 1.088205 ms
SDL_Delay(1) takes 1.086309 ms
SDL_Delay(1) takes 1.069637 ms
SDL_Delay(1) takes 1.068966 ms
SDL_Delay(1) takes 1.068637 ms
SDL_Delay(1) takes 1.081438 ms
SDL_Delay(1) takes 1.078134 ms
SDL_Delay(1) takes 1.085287 ms
SDL_Delay(1) takes 1.085804 ms
SDL_Delay(1) takes 1.085721 ms
SDL_Delay(1) takes 1.024315 ms
SDL_Delay(1) takes 1.081754 ms
SDL_Delay(1) takes 1.082592 ms
SDL_Delay(1) takes 1.085334 ms
SDL_Delay(1) takes 1.086600 ms
SDL_Delay(1) takes 1.085623 ms
SDL_Delay(1) takes 1.085648 ms
SDL_Delay(1) takes 1.085545 ms
SDL_Delay(1) takes 1.085480 ms
SDL_Delay(1) takes 1.082745 ms
SDL_Delay(1) takes 1.085969 ms
I assume handmade penguin is going to go up to the equivilant of episode 25, any updates on when the next chapter might be out?