devkitPro/libctru

linearAlloc overwrites Citro3D texture

Closed this issue · 9 comments

When allocating an audio-buffer using linearAlloc, the function seems to allocate space already used by a Citro3D texture.
I allocate the buffer using this:
u32 *audioBuffer = (u32*) linearAlloc(SAMPLESPERBUF * BYTESPERSAMPLE * 2);

When I run the function that fills this buffer and plays the sound, a part of a drawn Citro2D-sprite becomes a scrambled mess of pixels which I assume is the content of the buffer.

This happens no matter if I run the function normally or multi-threaded.

fincs commented

You're very likely overflowing said buffer when you run the function that fills the buffer. Please check your code.

I am using the code from the audio/streaming example of the devkitpro examples. Does that mean that one overflows the buffer as well?

Update: I tried just allocating the buffer and then filling it with useless data, and it still overwrites the texture.

u32 *audioBuffer = (u32*) linearAlloc(SAMPLESPERBUF * BYTESPERSAMPLE * 2);
memset(audioBuffer, '-', SAMPLESPERBUF * BYTESPERSAMPLE * 2);
fincs commented

What are the values of SAMPLESPERBUF and BYTESPERSAMPLE?
How are you creating/allocating the texture?

SAMPLESPERBUF and BYTESPERSAMPLE have these values:

#define SAMPLERATE 44100
#define SAMPLESPERBUF (SAMPLERATE / 30)
#define BYTESPERSAMPLE 4

The method I use to load and create the texture is located here:
https://github.com/StuntHacks/m3diaLib/blob/develop/m3dialib/source/graphics/texture.cpp#L111

And here I create the C2D_Image and create the sprite from it:
https://github.com/StuntHacks/m3diaLib/blob/develop/m3dialib/source/graphics/sprite.cpp#L188

fincs commented

The way you've chosen to convert graphics is very wasteful, not to mention the fact that you're manually converting graphics at runtime, which is resource intensive and redundant since tex3ds exists and it allows you to convert textures during the build process instead. Game assets should not be png/jpg, they should be converted to a 3DS friendly format at compile time, and they should be preferably grouped in texture atlases. In addition, you're storing unswizzled graphics inside the actual texture memory (albeit temporarily), and wasting time on swizzling it into a different buffer then copying it back. You should create a single staging buffer separate from the texture, decompress the texture there and then have tileTexture32 swizzle it directly into the actual texture memory.

In Sprite::setTexture, you're creating the C2D_Image with a static Tex3DS_SubTexture object that is the same for every single sprite because it is a static variable. As soon as you call setTexture again, the old subtexture will be overwritten with the values corresponding to the new texture. The subtexture object should be a member field of the Sprite class.

I actually noticed the problem with the static SubTexture already and I already fixed that, I just didn't push it yet. However, that doesn't fix the problem either.
I'll try using tex3ds for texture conversion, maybe that'll help (and if not, it'll at least become way faster)

Can confirm. I got a similar issue in the past while using citro3d and citro2d, where a texture kept on overwriting a previous texture. I managed to fix it but I don't remember what I did

fincs commented

Closing because this issue strongly smells of user error. A certain user had a similar bug in the past, and after many weeks of intense debugging it was discovered that in fact a buffer overrun was present in the code; after fixing that all issues disappeared.