mirror of
https://github.com/thug1src/thug.git
synced 2025-01-22 05:43:47 +00:00
362 lines
9.2 KiB
C++
362 lines
9.2 KiB
C++
#include <core/defines.h>
|
|
#include <eekernel.h>
|
|
#include <eeregs.h>
|
|
#include "texture.h"
|
|
#include "group.h"
|
|
#include "render.h"
|
|
#include "gs.h"
|
|
#include "switches.h"
|
|
#include <sys\profiler.h>
|
|
|
|
//#undef __USE_PROFILER__
|
|
|
|
|
|
/*
|
|
|
|
Mick Notes:
|
|
|
|
All interrupts are set up in the "InitialiseEngine" function of nx_init.cpp
|
|
|
|
There are three types of interrupt covered here
|
|
|
|
1) GIF Interrupt - Used to signal the completion of texture upload to VRAM
|
|
2) GS Interrupt - Used to signal the completion of GS rendering (drawing polygons)
|
|
3) VIF Interrupt - NOT USED, could be used like the GS interrupt, but unreliable.
|
|
|
|
There are two types of activity going on in parallel: Upload and Render
|
|
|
|
Whenever one of these finishes, it causes an interrupt.
|
|
|
|
There is no way of knowing in advance what order the tasks will finish in
|
|
so we must handle all possible cases.
|
|
|
|
At any time, either upload or render might be "Stalled". In this case we are waiting
|
|
for something before we can start rendering or uploading a new group. Stalls are not
|
|
good, as the relevent processor is sat idle. We want to minimize stalls as much as
|
|
possible.
|
|
|
|
Stalls happen when:
|
|
|
|
- The initial render group is waiting for its textures to upload.
|
|
(?) The renderer is always stalled on the first group
|
|
- An upload group want to use some VRAM that is used by a group
|
|
that is currently rendering.
|
|
- A render group is waiting for it's textures to upload. This could
|
|
happen if a group renders quicker than the next groups uploads.
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace NxPs2
|
|
{
|
|
|
|
|
|
#define START_UPLOAD() \
|
|
{ \
|
|
*D2_QWC = 0; \
|
|
*D2_TADR = (uint)sGroup::pUploadGroup->pUpload[!render::Field]; \
|
|
*D2_CHCR = 0x105; \
|
|
UploadStalled = 0; \
|
|
}
|
|
|
|
#if GS_INTERRUPT
|
|
#define START_RENDER() \
|
|
{ \
|
|
*D1_QWC = 0; \
|
|
*D1_TADR = (uint)sGroup::pRenderGroup->pRender[!render::Field]; \
|
|
*D1_CHCR = 0x145; \
|
|
RenderStalled = 0; \
|
|
}
|
|
#endif
|
|
|
|
#if VIF1_INTERRUPT
|
|
#define START_RENDER() \
|
|
{ \
|
|
if (sGroup::pRenderGroup != sGroup::pHead) \
|
|
*VIF1_FBRST = 1<<3; \
|
|
else \
|
|
{ \
|
|
*D1_QWC = 0; \
|
|
*D1_TADR = (uint)sGroup::pRenderGroup->pRender[!render::Field]; \
|
|
*D1_CHCR = 0x145; \
|
|
} \
|
|
}
|
|
#endif
|
|
|
|
#define NO_VRAM_CONFLICT() \
|
|
( \
|
|
sGroup::pRenderGroup->VramStart >= sGroup::pUploadGroup->VramEnd || \
|
|
sGroup::pUploadGroup->VramStart >= sGroup::pRenderGroup->VramEnd \
|
|
)
|
|
|
|
|
|
volatile uint32 UploadStalled, RenderStalled;
|
|
|
|
|
|
|
|
// handler called when an upload finishes
|
|
|
|
int GifHandler(int Cause)
|
|
{
|
|
if (!sGroup::pUploadGroup) // Mick: Might not actually be anything to upload, if p_memview was uploading
|
|
goto EXIT;
|
|
|
|
// we've finished uploading a group
|
|
sGroup::pUploadGroup = sGroup::pUploadGroup->pNext;
|
|
while (sGroup::pUploadGroup && !sGroup::pUploadGroup->Used[!render::Field]) // if exists, but not used
|
|
{
|
|
sGroup::pUploadGroup = sGroup::pUploadGroup->pNext; // then skip groups until reach end, or find one that is used
|
|
}
|
|
|
|
|
|
# ifdef __USE_PROFILER__
|
|
Sys::DMAProfiler->PopContext();
|
|
# endif // __USE_PROFILER__
|
|
|
|
// is there another group to upload?
|
|
if (sGroup::pUploadGroup)
|
|
{
|
|
|
|
|
|
// was there a stalled render?
|
|
if (RenderStalled)
|
|
{
|
|
// kick off the stalled render
|
|
# ifdef __USE_PROFILER__
|
|
Sys::VUProfiler->PushContext( sGroup::pRenderGroup->profile_color );
|
|
# endif // __USE_PROFILER__
|
|
START_RENDER();
|
|
|
|
// is the next upload safe?
|
|
if (NO_VRAM_CONFLICT())
|
|
{
|
|
// kick off the next upload
|
|
# ifdef __USE_PROFILER__
|
|
Sys::DMAProfiler->PushContext( sGroup::pUploadGroup->profile_color );
|
|
# endif // __USE_PROFILER__
|
|
START_UPLOAD();
|
|
}
|
|
else
|
|
{
|
|
// stall the next upload
|
|
UploadStalled = 1;
|
|
}
|
|
}
|
|
|
|
else// there's a render in progress
|
|
{
|
|
// since we just finished an upload, then the render in progress MUST
|
|
// be using the previously uploaded group
|
|
// so there is no way that we can start a new upload until that render finishes.
|
|
// so, stall the next upload
|
|
UploadStalled = 1;
|
|
}
|
|
}
|
|
|
|
else// no more groups to upload
|
|
{
|
|
// was the final render stalled?
|
|
if (RenderStalled)
|
|
{
|
|
// kick it off
|
|
# ifdef __USE_PROFILER__
|
|
Sys::VUProfiler->PushContext( sGroup::pRenderGroup->profile_color );
|
|
# endif // __USE_PROFILER__
|
|
START_RENDER();
|
|
}
|
|
}
|
|
|
|
EXIT:
|
|
ExitHandler();
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
// handler called when a render finishes (gs version)
|
|
|
|
int GsHandler(int Cause)
|
|
{
|
|
// mask GS interrupts
|
|
*GS_IMR = PackIMR(1,1,1,1);
|
|
|
|
// reset SIGNAL event bit
|
|
*GS_CSR = *GS_CSR & ~(uint64)0x30F | 1;
|
|
|
|
// reset signal bit
|
|
*GS_SIGLBLID &= ~(uint64)1;
|
|
|
|
// maybe it was a false alarm...
|
|
if (!sGroup::pRenderGroup) // if nothing currently rendering, then we've finished!!
|
|
goto EXIT;
|
|
|
|
// we've finished rendering a group, so find the next group to render
|
|
sGroup::pRenderGroup = sGroup::pRenderGroup->pNext;
|
|
while (sGroup::pRenderGroup && !sGroup::pRenderGroup->Used[!render::Field]) // if exists, but not used
|
|
{
|
|
sGroup::pRenderGroup = sGroup::pRenderGroup->pNext; // then skip groups until reach end, or find one that is used
|
|
}
|
|
|
|
# ifdef __USE_PROFILER__
|
|
Sys::VUProfiler->PopContext();
|
|
# endif // __USE_PROFILER__
|
|
|
|
|
|
// is there another group to render?
|
|
if (sGroup::pRenderGroup)
|
|
{
|
|
// was there a stalled upload?
|
|
if (UploadStalled)
|
|
{
|
|
// is the next render waiting for the stalled upload?
|
|
// (i.e., they both are the same group)
|
|
if (sGroup::pRenderGroup == sGroup::pUploadGroup)
|
|
{
|
|
// kick off the stalled upload
|
|
# ifdef __USE_PROFILER__
|
|
Sys::DMAProfiler->PushContext( sGroup::pUploadGroup->profile_color );
|
|
# endif // __USE_PROFILER__
|
|
START_UPLOAD();
|
|
|
|
// but stall the next render
|
|
// as this upload group is needed for this render
|
|
RenderStalled = 2;
|
|
}
|
|
else
|
|
{
|
|
// kick off the next render, as it's from a previous group
|
|
# ifdef __USE_PROFILER__
|
|
Sys::VUProfiler->PushContext( sGroup::pRenderGroup->profile_color );
|
|
# endif // __USE_PROFILER__
|
|
START_RENDER();
|
|
|
|
// is the next upload safe?
|
|
if (NO_VRAM_CONFLICT())
|
|
{
|
|
// kick off the next upload
|
|
# ifdef __USE_PROFILER__
|
|
Sys::DMAProfiler->PushContext( sGroup::pUploadGroup->profile_color );
|
|
# endif // __USE_PROFILER__
|
|
START_UPLOAD();
|
|
}
|
|
}
|
|
}
|
|
|
|
// is there an upload in progress?
|
|
// (Mick: Does it make sense to also check to see if the upload group is the same as the render group?
|
|
// or is that always the case, and that's why Mike is not checking it?)
|
|
else if (sGroup::pUploadGroup)
|
|
{
|
|
// stall the next render
|
|
RenderStalled = 1;
|
|
}
|
|
|
|
// no uploads left
|
|
else
|
|
{
|
|
// kick off the final render
|
|
# ifdef __USE_PROFILER__
|
|
Sys::VUProfiler->PushContext( sGroup::pRenderGroup->profile_color );
|
|
# endif // __USE_PROFILER__
|
|
START_RENDER();
|
|
}
|
|
}
|
|
|
|
EXIT:
|
|
// re-enable GS interrupts
|
|
*GS_IMR = PackIMR(0,1,1,1);
|
|
|
|
ExitHandler();
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// handler called when a render finishes (vif version)
|
|
// (Mick: not currently used, ignore for now)
|
|
int Vif1Handler(int Cause)
|
|
{
|
|
// make sure the mark register gives the go-ahead
|
|
if (*VIF1_MARK != 1)
|
|
goto EXIT;
|
|
|
|
// maybe it was a false alarm...
|
|
if (!sGroup::pRenderGroup)
|
|
goto EXIT;
|
|
|
|
// we've finished rendering a group
|
|
sGroup::pRenderGroup = sGroup::pRenderGroup->pNext; // get next group
|
|
|
|
// is there another group to render?
|
|
if (sGroup::pRenderGroup)
|
|
{
|
|
// was there a stalled upload?
|
|
if (UploadStalled)
|
|
{
|
|
// is the next render waiting for the stalled upload?
|
|
if (sGroup::pRenderGroup == sGroup::pUploadGroup)
|
|
{
|
|
// kick off the stalled upload
|
|
# ifdef __USE_PROFILER__
|
|
Sys::DMAProfiler->PushContext( sGroup::pUploadGroup->profile_color );
|
|
# endif // __USE_PROFILER__
|
|
START_UPLOAD();
|
|
UploadStalled = 0;
|
|
|
|
// but stall the next render
|
|
RenderStalled = 2;
|
|
}
|
|
else
|
|
{
|
|
// kick off the next render
|
|
# ifdef __USE_PROFILER__
|
|
Sys::VUProfiler->PushContext( sGroup::pRenderGroup->profile_color );
|
|
# endif // __USE_PROFILER__
|
|
START_RENDER();
|
|
|
|
// is the next upload safe?
|
|
if (NO_VRAM_CONFLICT())
|
|
{
|
|
// kick off the next upload
|
|
# ifdef __USE_PROFILER__
|
|
Sys::DMAProfiler->PushContext( sGroup::pUploadGroup->profile_color );
|
|
# endif // __USE_PROFILER__
|
|
START_UPLOAD();
|
|
UploadStalled = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// is there an upload in progress?
|
|
else if (sGroup::pUploadGroup)
|
|
{
|
|
// stall the next render
|
|
RenderStalled = 1;
|
|
}
|
|
|
|
// no uploads left
|
|
else
|
|
{
|
|
// kick off the final render
|
|
# ifdef __USE_PROFILER__
|
|
Sys::VUProfiler->PushContext( sGroup::pRenderGroup->profile_color );
|
|
# endif // __USE_PROFILER__
|
|
START_RENDER();
|
|
}
|
|
}
|
|
|
|
EXIT:
|
|
ExitHandler();
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace NxPs2
|
|
|