It seems like the playdate APIs file read function either thrashes the memory or is leaking memory triggering a crash later on. This only happens on the physical device not in the simulator.
I've tested this out on Linux in Playdate version "1.11" and "2.0.0.beta.2" and both seem to show the same behaviour.
How to reproduce:
- Have a large enough file to load (I've got a BMP file that I'm reading that is 2.1 MB large for my example)
- Run the following code somewhere in your game (either in setup or main-loop of the game should be fine)
unsigned char *loadBMPDataFromImgMap(PlaydateAPI *pd, unsigned char* file, int xOffset, int yOffset, int targetWidth, int targetHeight)
{
char header[54];
int dataPos;
int imageSize;
unsigned char *data = NULL;
unsigned char *data_2bitsPerPixel = NULL;
int width;
int height;
SDFile* bmpData = pd->file->open(file, kFileRead);
if(bmpData)
{
pd->system->logToConsole("loadBMPDataFromImgMap read %s", file);
// Read the header
pd->file->read(bmpData, header, sizeof(char) * 54);
dataPos = *(int*)&(header[0x0A]);
imageSize = *(int*)&(header[0x22]);
width = *(int*)&(header[0x12]);
height = *(int*)&(header[0x16]);
// Some BMP files are misformatted, guess missing information
if (imageSize == 0)
{
imageSize = width * height * 3; // 3 : one byte for each Red, Green and Blue component
pd->system->logToConsole("Image size missing");
}
if (dataPos == 0)
{
dataPos = 54; // The BMP header is done that way
}
pd->system->logToConsole("dataPos %d", dataPos);
// Lock memory for the BMP data
data = pd->system->realloc(NULL, imageSize * sizeof(unsigned char));
pd->system->logToConsole("locked mem for data %p, size : %d", data, imageSize);
// Read the data and then close the file
int dataRead = pd->file->read(bmpData, data, sizeof(unsigned char) * imageSize);
pd->file->close(bmpData);
bmpData = NULL;
pd->system->logToConsole("read back %d from file %s", dataRead, file);
pd->system->realloc(data, 0);
pd->system->logToConsole("freed data");
}
return NULL;
}
// Put this inside setup call or in the main game loop
for(int i = 0; i < 100; i++)
{
loadBMPDataFromImgMap(pd, "images/guard_walk_h.bmp", 0, 0, 0, 0);
}
(xoffset, yoffset, targetWidth, and targetHeight are not used in the function)
After a couple of iterations in the foor loop calling loadBMPDataFromImgMap the physical device crashes. If you remove the following line from the function the crash goes away:
int dataRead = pd->file->read(bmpData, data, sizeof(unsigned char) * imageSize);
It seems like file->read is the culprit. I did try running the same for loop in setup but with much fewer iterations (10 iterations) and I'm not able to see any memory leaks (I've tested a version where loadBMPDataFromImgMap never gets called and the memory foot print seems to be the exact same).
I'm probably able to work around this by simply loading my image map once and just reusing the data from the file - but there seems like there is some issue with the file read function here that mainly shows up when reading large quantities of data (I never saw this issue until I started loading in my larger "image maps" that contains frames of animation). My code just opens/closes the file repetedly as it is building each individual frame but I can refactor it to just re-use the data I've loaded.
This does however seem like a bug in the playdate API and would ofc be good to have this fixed.
Kindly,
/Jimmie