I think it's time to introduce some more advanced techniques rather than the classic 'fill->draw->wait' model. So I did some research on GE signals, and got a few questions:
1) What's happening to GE before the signal handler returns? Is it just waiting there? Or maybe continue execution till it reaches the stall address/stop command as usual?
Well, personally I prefer the prior one...abviously it's more simple. But I'm afraid it's probably not the truth? Since according to the 'signal' sample in the SDK:
Code: Select all
void render_billboards(unsigned int i)
{
if (i >= g_context.iterationCount) return;
Vertex* vbuffer = g_context.vbuffer[i%NUM_VERTEX_BUFFERS];
int sliceCount = NUM_SLICES / g_context.iterationCount;
// fill current vertex buffer if we just started
if (i == 0)
{
create_modified_torus_billboards(vbuffer,(float*)&g_context.world, g_context.sint, sliceCount*i, sliceCount);
}
// render previously generated vertex buffer
sceGumMatrixMode(GU_MODEL);
sceGumLoadMatrix(&g_context.world);
sceGumDrawArray(GU_SPRITES,GU_TEXTURE_32BITF|GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_3D,sliceCount*NUM_ROWS*2,0,vbuffer);
g_context.vertsRendered += sliceCount*NUM_ROWS*2;
// fill next vertex buffer for future rendering
int nextI = i + 1;
if (nextI < g_context.iterationCount )
{
Vertex* vbufferNext;
vbufferNext = g_context.vbuffer[nextI%NUM_VERTEX_BUFFERS];
create_modified_torus_billboards(vbufferNext,(float*)&g_context.world, g_context.sint, sliceCount*nextI, sliceCount);
}
#ifdef USING_SIGNALS
// send a signal when rendering was completed
// signals 0x01..0x03 - seems to be available for custom usage
sceGuSignal( 1, nextI );
// HACK: keeps CPU waiting until all jobs were submitted for GPU
if (nextI == g_context.iterationCount)
sceGuFinish();
#endif
}
So...it should be 'asynchronized'? Also I've noticed that in SDK source callbackSig.c, a kernel event flag is set each time after the user handler returns:
Code: Select all
void callbackSig(int id, void* arg)
{
GuSettings* settings = (GuSettings*)arg;
settings->signal_history[(settings->signal_offset++) & 15] = id & 0xffff;
if (settings->sig)
settings->sig(id & 0xffff);
sceKernelSetEventFlag(settings->kernel_event_flag,1);
}
So here comes another question:
2) If it's 'asynchronized', then what happens when GE raised another signal while we are still processing the last signal interrupt? Is our signal handler must be reentrant? Or system will suppress the interrupt until we returned from the last one?
Any ideas? Any detailed info? Thanks.
BTW, I think there must be something wrong with the description of sceGuSignal():
Code: Select all
/**
* Trigger signal to call code from the command stream
*
* Available behaviors are:
* - GU_BEHAVIOR_SUSPEND - Stops display list execution until callback function finished
* - GU_BEHAVIOR_CONTINUE - Do not stop display list execution during callback
*
* @param signal - Signal to trigger
* @param behavior - Behavior type
**/
void sceGuSignal(int signal, int behavior);