Ian Micheal wrote:kazade: Yeah I think they're misreading it a bit - we're definitely missing the dynamic opb area, and that will result in glitches if you render enough stuff, but I don't believe there's an overlapping area
You have got the very latestest version ? as what your talking about was solved?
If you cant get my version of sdl to work i can try doing it for you since i have been dealing with dreamcast and sdl since 2002 and solving that tick your talking about on all my ports..
only problem i see is i use gcc4.7 and your compiled core will prollly not work i have not tried yet
My interpretation of the buffer allocation code works like this:
The buf->opb variable in the KOS PVR driver does two things. It specifies the high end of the dynamic OPB, and the low end of the static OPB. The dynamic OPB starts right below buf->opb, and grows DOWN to buf->opb - buf->opb_size. The lines "buf->opb_size = 0x50580 + polybuf; outaddr += buf->opb_size;" in the old code were allocating space for the dynamic OPB. The new code sets the size of the dynamic OPB to be the size of the static OPB, and doesn't allocate any specific area for the dynamic OPB. As the dynamic OPB grows down, it overlaps the high end of the vertex buffer. With the old code, the TA would prevent either one growing to the point that they overlap, but now the TA doesn't do that.
The function pvr_sync_reg_buffer() in pvr_misc.c sets the TA OPB registers. The names of the constants in KOS don't really indicate what they do, so I've commented them:
Code: Select all
PVR_SET(PVR_TA_OPB_START, buf->opb); //Static OPB start
PVR_SET(PVR_TA_OPB_END, buf->opb - buf->opb_size); //Dynamic OPB end. It grows down, see the minus?
PVR_SET(PVR_TA_VERTBUF_START, buf->vertex);
PVR_SET(PVR_TA_VERTBUF_END, buf->vertex + buf->vertex_size);
PVR_SET(PVR_TA_OPB_INIT, buf->opb); //Dynamic OPB start (high end of dynamic OPB)
The math for the buffers in the current driver works out like this:
- PVR_TA_VERTBUF_END = buf->vertex + buf->vertex_size
- PVR_TA_OPB_INIT = buf->vertex + buf->vertex_size (== buf->opb)
- PVR_TA_OPB_END = buf->vertex + buf->vertex_size - buf->opb_size (== buf->opb - buf->opb_size)
There is a register to read the position of the next dynamic OPB allocation, PVR_TA_OPB_POS, which would be useful for testing and seeing how much of the dynamic OPB is used. For some reason, you need to left shift it by two to get the real address. ("PVR_GET(PVR_TA_OPB_POS) << 2") You could be able to see the position starts below PVR_TA_VERTBUF_END and decreases as more OPB blocks are allocated.
To make an OPB stress test program, I would do this:
- Draw a lot of polygons with a small vertex buffer, so that you don't need to submit so much to get the vertices and dynamic OPB to meet up.
- Draw everything really close together, so the OPB buckets they touch keep overflowing and require dynamic OPB allocations.
- Draw triangle strips, not individual triangles or sprites. There seems to be a PVR feature that combines multiple individual triangles or sprites into a single OPB entry, but strips always seem to get their own entry and would use up the OPBs faster.
- Use a bin size of 8, so that the static OPB gets used up quickly.
When I said that one leak was fixed, I was talking about the line "outaddr += buf->opb_size; /* Do we _really_ need this twice? */". But looking at the old code again, it looks like the old OPB initialization code DID have a second bug. "buf->opb_size = 0x50580 + polybuf;" should have been just "buf->opb_size = 0x50580;", I think? Polybuf was set to the end of the vertex buffer, so it would set the dynamic OPB size to be the size of the vertex buffer plus 0x50580. (And a dynamic OPB of size 0x50580 is already overkill.) So it seems I was wrong, and there was a second leak, but the fix for the leak introduced a different bug. (By my reading, at least.)
As for the clicking, I tried replacing my default KOS SDL library with yours, but the clicking remained. I double checked a couple times to make sure it was using the new SDL. Maybe the issue is with Gens4All?
The SDL audio callback I'm using in Gens4All currently looks like this.
Code: Select all
void
proc (void *user, Uint8 * buffer, int len)
{
user=audiobuf;
if(!user) {
memset(buffer,len,0);
return;
}
if (audio_len < len) {
//printf("U"); fflush(stdout);
//Audio buffer underflow, copy what we have, pad out the rest of the buffer with zeroes
SDL_LockAudio ();
memcpy (buffer, user, audio_len);
memset(buffer + audio_len, 0, len - audio_len);
SDL_UnlockAudio ();
if (soundrecenabled) {
//If recording, make a copy of what was sent to SDL
memcpy (soundrec + soundrecpos, user, audio_len);
soundrecpos += audio_len;
}
audio_len = 0;
} else {
//printf("f"); fflush(stdout);
//We have more samples in the emulated buffer than SDL needs.
SDL_LockAudio ();
memcpy (buffer, user, len);
SDL_UnlockAudio ();
if (soundrecenabled) {
//If recording, make a copy of what was sent to SDL
memcpy (soundrec + soundrecpos, user, len);
soundrecpos += len;
}
//Remove the part of the buffer that was sent to SDL
audio_len -= len;
memmove (user, (unsigned char *) user + len, audio_len);
}
if (soundrecenabled && (soundrecpos > 500*1024)) {
printf("Rec over\n"); fflush(stdout);
soundrecenabled = 0;
}
}
The variable soundrecenabled was used to enable the dump test I did to check if the clicking was in the emulated audio stream. Are the lock and unlock audio calls needed here? I didn't notice any changes whether or not they were there. The "samples" parameter of SDL's audio struct is set to 1024.
Using the printfs, I've checked that the emulated buffer is not underflowing when the clicking occurs. It underflows for the first few calls when the emulator first starts, but when the music for Phantasy Star 2's title screen plays (with clicking), it's printing out "f", so SDL seems to be getting good data.
On Phantasy Star 2, the clicking happens on a regular interval multiple times a second in the left channel. A lower sample parameter in the SDL audio init struct results in more frequent clicking, and a lower frequency results in less frequent clicking. So clicking seems tied to how often the audio buffer needs to be filled. Clicking doesn't happen when the Genesis is silent.
It makes me think that maybe there's an off-by-one error in SDL when it copies the samples into sound RAM, so something like one byte of an old sample remains by accident?