mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2024-11-14 13:27:41 -07:00
new feature: crashes
This commit is contained in:
parent
c05c79321a
commit
fb5b2c299c
@ -344,7 +344,7 @@ public:
|
|||||||
// and beginning reading the second scanline of a scanline pair.
|
// and beginning reading the second scanline of a scanline pair.
|
||||||
static constexpr int GPU2DReadScanline = 256 * TimingFrac; // 256 | the time it takes to read a scanline.
|
static constexpr int GPU2DReadScanline = 256 * TimingFrac; // 256 | the time it takes to read a scanline.
|
||||||
static constexpr int GPU2DReadSLPair = 1618 * TimingFrac; // 1618 | notably the same as the scanline increment.
|
static constexpr int GPU2DReadSLPair = 1618 * TimingFrac; // 1618 | notably the same as the scanline increment.
|
||||||
static constexpr int InitGPU2DTimeout = 51874 * TimingFrac; // 51618? | when it finishes reading the first scanline.
|
static constexpr int InitGPU2DTimeout = 52128 * TimingFrac; // 51618? 51874? | when it finishes reading the first scanline.
|
||||||
static constexpr int GPU2D48Scanlines = GPU2DReadSLPair * 24; // time to read 48 scanlines.
|
static constexpr int GPU2D48Scanlines = GPU2DReadSLPair * 24; // time to read 48 scanlines.
|
||||||
static constexpr int FrameLength = ScanlineReadInc * 263; // how long the entire frame is. TODO: Verify if we actually need this?
|
static constexpr int FrameLength = ScanlineReadInc * 263; // how long the entire frame is. TODO: Verify if we actually need this?
|
||||||
|
|
||||||
@ -362,6 +362,8 @@ public:
|
|||||||
static constexpr int FinalPassLen = 500 * TimingFrac; // 496 (might technically be 500?) | the next scanline cannot begin while a scanline's final pass is in progress
|
static constexpr int FinalPassLen = 500 * TimingFrac; // 496 (might technically be 500?) | the next scanline cannot begin while a scanline's final pass is in progress
|
||||||
// (can be interpreted as the minimum amount of cycles for the next scanline
|
// (can be interpreted as the minimum amount of cycles for the next scanline
|
||||||
// pair to start after the previous pair began) (related to final pass?)
|
// pair to start after the previous pair began) (related to final pass?)
|
||||||
|
static constexpr int ScanlinePushDelay = 242 * TimingFrac;
|
||||||
|
static constexpr int TimeoutIncrement = 2130 * TimingFrac;
|
||||||
static constexpr int ScanlineIncrementold = 1618 * TimingFrac; // 1618 | how much to regain per scanline pair
|
static constexpr int ScanlineIncrementold = 1618 * TimingFrac; // 1618 | how much to regain per scanline pair
|
||||||
static constexpr int ScanlineIncrement = 2114 * TimingFrac; // 2114 | how much time a scanline pair "gains"
|
static constexpr int ScanlineIncrement = 2114 * TimingFrac; // 2114 | how much time a scanline pair "gains"
|
||||||
static constexpr int AbortIncrement = 12 * TimingFrac; // 12 | how much extra to regain after an aborted scanline (total 2126)
|
static constexpr int AbortIncrement = 12 * TimingFrac; // 12 | how much extra to regain after an aborted scanline (total 2126)
|
||||||
|
@ -1747,18 +1747,14 @@ u16 SoftRenderer::BeginPushScanline(s32 y, s32 pixelstodraw)
|
|||||||
{
|
{
|
||||||
// push the finished scanline to the appropriate frame buffers.
|
// push the finished scanline to the appropriate frame buffers.
|
||||||
// if a scanline is late enough to intersect with the 2d engine read time it will be partially drawn
|
// if a scanline is late enough to intersect with the 2d engine read time it will be partially drawn
|
||||||
/*
|
|
||||||
u16 start;
|
u16 start;
|
||||||
if (pixelstodraw >= 256)
|
if (pixelstodraw >= 256) // if scheduled after or 256 cycles before a scanline read render full scanline
|
||||||
{
|
{
|
||||||
start = 0;
|
start = 0;
|
||||||
pixelstodraw = 256;
|
pixelstodraw = 256;
|
||||||
}
|
}
|
||||||
else if (pixelstodraw <= 0)
|
else // render partial scanline
|
||||||
{
|
|
||||||
return 256;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
start = ScanlineWidth - pixelstodraw;
|
start = ScanlineWidth - pixelstodraw;
|
||||||
|
|
||||||
@ -1771,10 +1767,6 @@ u16 SoftRenderer::BeginPushScanline(s32 y, s32 pixelstodraw)
|
|||||||
u8 bufferpos = y % 48;
|
u8 bufferpos = y % 48;
|
||||||
memcpy(&RDBuffer[bufferpos*ScanlineWidth+start], &ColorBuffer[y*ScanlineWidth+start], 4 * pixelstodraw);
|
memcpy(&RDBuffer[bufferpos*ScanlineWidth+start], &ColorBuffer[y*ScanlineWidth+start], 4 * pixelstodraw);
|
||||||
return start;
|
return start;
|
||||||
*/
|
|
||||||
u8 bufferpos = y % 48;
|
|
||||||
memcpy(&RDBuffer[bufferpos*ScanlineWidth], &ColorBuffer[y*ScanlineWidth], 4*ScanlineWidth);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftRenderer::ReadScanline(s32 y)
|
void SoftRenderer::ReadScanline(s32 y)
|
||||||
@ -1801,11 +1793,12 @@ void SoftRenderer::RenderPolygons(GPU& gpu, Polygon** polygons, int npolys)
|
|||||||
SetupPolygon(&PolygonList[j++], polygons[i]);
|
SetupPolygon(&PolygonList[j++], polygons[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//init internal buffer
|
||||||
ClearBuffers(gpu);
|
ClearBuffers(gpu);
|
||||||
|
|
||||||
|
// init all this junk i need to keep track of
|
||||||
s32 rasterevents[RasterEvents_MAX];
|
s32 rasterevents[RasterEvents_MAX];
|
||||||
s32 y = 0;
|
s32 y = 0;
|
||||||
s32 yold;
|
|
||||||
rasterevents[RenderStart] = 0;
|
rasterevents[RenderStart] = 0;
|
||||||
rasterevents[RenderFinal] = INT_MAX/2;
|
rasterevents[RenderFinal] = INT_MAX/2;
|
||||||
rasterevents[PushScanline] = INT_MAX/2;
|
rasterevents[PushScanline] = INT_MAX/2;
|
||||||
@ -1817,14 +1810,16 @@ void SoftRenderer::RenderPolygons(GPU& gpu, Polygon** polygons, int npolys)
|
|||||||
s32 rastertimingodd = 0;
|
s32 rastertimingodd = 0;
|
||||||
u8 scanlinesread = 0;
|
u8 scanlinesread = 0;
|
||||||
u8 scanlinespushed = 0;
|
u8 scanlinespushed = 0;
|
||||||
|
u8 scanlinespushed2 = 0;
|
||||||
s16 scanlinesrendered = 0;
|
s16 scanlinesrendered = 0;
|
||||||
s8 scanlineswaiting = 0;
|
s16 scanlineswaiting = 0;
|
||||||
u8 nextevent;
|
u8 nextevent;
|
||||||
bool doa, dob, fina;
|
u16 leftovers;
|
||||||
u16 leftoversa, leftoversb;
|
|
||||||
|
|
||||||
while ((scanlinesread < 192 || scanlinespushed < 192) && (RasterTiming < FrameLength))
|
// until all scanlines have been pushed and read continue looping... CHECKME: unless its time for the next 3d frame should begin
|
||||||
|
while ((scanlinesread < 192 || scanlinespushed2 < 192) && (RasterTiming < FrameLength))
|
||||||
{
|
{
|
||||||
|
// check all events to find the earliest scheduled one
|
||||||
nextevent = 0;
|
nextevent = 0;
|
||||||
for (s32 i = 1; i < RasterEvents_MAX; i++)
|
for (s32 i = 1; i < RasterEvents_MAX; i++)
|
||||||
{
|
{
|
||||||
@ -1832,117 +1827,115 @@ void SoftRenderer::RenderPolygons(GPU& gpu, Polygon** polygons, int npolys)
|
|||||||
nextevent = i;
|
nextevent = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if all events are scheduled for after the next frame begins, ABORT
|
||||||
|
if (rasterevents[nextevent] >= FrameLength) break;
|
||||||
|
|
||||||
switch (nextevent)
|
switch (nextevent)
|
||||||
{
|
{
|
||||||
case RenderStart:
|
|
||||||
|
|
||||||
|
// initial rendering pass (polygons, texturing, etc.) (variable cycle length)
|
||||||
|
case RenderStart:
|
||||||
|
// set current raster time to the start of the event
|
||||||
RasterTiming = rasterevents[RenderStart];
|
RasterTiming = rasterevents[RenderStart];
|
||||||
|
|
||||||
{
|
{
|
||||||
s32 rastertimingeven = 0;
|
s32 rastertimingeven = 0;
|
||||||
s32 rastertimingodd = 0;
|
s32 rastertimingodd = 0;
|
||||||
|
// scanlines are rendered in pairs of two
|
||||||
RenderScanline(gpu, y, j, &rastertimingeven);
|
RenderScanline(gpu, y, j, &rastertimingeven);
|
||||||
RenderScanline(gpu, y+1, j, &rastertimingodd);
|
RenderScanline(gpu, y+1, j, &rastertimingodd);
|
||||||
|
|
||||||
|
// a new scanline pair cannot begin until both scanlines are finished.
|
||||||
s32 timespent = std::max(rastertimingeven, rastertimingodd);
|
s32 timespent = std::max(rastertimingeven, rastertimingodd);
|
||||||
|
|
||||||
|
// a new scanline pair cannot begin until the finishing pass + push is done.
|
||||||
if ((RasterTiming + timespent) < (RasterTiming+FinalPassLen))
|
if ((RasterTiming + timespent) < (RasterTiming+FinalPassLen))
|
||||||
RasterTiming += FinalPassLen;
|
RasterTiming += FinalPassLen;
|
||||||
else
|
else
|
||||||
RasterTiming += timespent;
|
RasterTiming += timespent;
|
||||||
|
|
||||||
|
// 12 cycles at the end of the scanline are always used, unless the scanline got within 12 cycles of timing out. Don't ask why, it just does.
|
||||||
s32 timeoutdist = ScanlineTimeout - RasterTiming;
|
s32 timeoutdist = ScanlineTimeout - RasterTiming;
|
||||||
RasterTiming += std::clamp(timeoutdist, 0, 12);
|
RasterTiming += std::clamp(timeoutdist, 0, 12);
|
||||||
}
|
}
|
||||||
|
if (ScanlineTimeout == INT_MAX/2) ScanlineTimeout = rasterevents[ScanlineRead] - FinalPassLen;
|
||||||
|
else ScanlineTimeout += TimeoutIncrement;
|
||||||
|
// schedule next scanline pair + the final pass of the latest pair
|
||||||
rasterevents[RenderFinal] = RasterTiming;
|
rasterevents[RenderFinal] = RasterTiming;
|
||||||
rasterevents[RenderStart] = RasterTiming+RastDelay;
|
if (y < 190) rasterevents[RenderStart] = RasterTiming+RastDelay; // scheduled 4 cycles late (presumably due to initial polygon timing shenanigans?)
|
||||||
//if (y < 190) rasterevents[RenderStart] = RasterTiming+RastDelay;
|
else rasterevents[RenderStart] = INT_MAX/2;
|
||||||
//else rasterevents[RenderStart] = INT_MAX/2;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RenderFinal:
|
|
||||||
|
|
||||||
rasterevents[PushScanline] = rasterevents[RenderFinal] + 4;
|
|
||||||
|
|
||||||
|
// final rendering pass (edge marking, anti-aliasing, fog) (fixed length of 496 (maybe 500?) cycles)
|
||||||
|
case RenderFinal:
|
||||||
|
|
||||||
|
// schedule a scanline push event
|
||||||
|
rasterevents[PushScanline] = rasterevents[RenderFinal] + ScanlinePushDelay;
|
||||||
|
|
||||||
|
// if the first scanline pair was just finished only render one scanline
|
||||||
if (y >= 2)
|
if (y >= 2)
|
||||||
{
|
{
|
||||||
ScanlineFinalPass(gpu.GPU3D, y-1);
|
ScanlineFinalPass(gpu.GPU3D, y-1);
|
||||||
scanlinesrendered++;
|
scanlinesrendered++;
|
||||||
doa = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
doa = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the last scanline pair was just finished only render one scanline
|
||||||
if (y <= 192)
|
if (y <= 192)
|
||||||
{
|
{
|
||||||
ScanlineFinalPass(gpu.GPU3D, y);
|
ScanlineFinalPass(gpu.GPU3D, y);
|
||||||
scanlinesrendered++;
|
scanlinesrendered++;
|
||||||
|
// unschedule final pass event
|
||||||
rasterevents[RenderFinal] = INT_MAX/2;
|
rasterevents[RenderFinal] = INT_MAX/2;
|
||||||
}
|
}
|
||||||
else
|
else // schedule next final pass event to immediately after the current one
|
||||||
rasterevents[RenderFinal] += FinalPassLen;
|
rasterevents[RenderFinal] += FinalPassLen;
|
||||||
|
|
||||||
|
// increment y for main rendering passes
|
||||||
y += 2;
|
y += 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
// push scanlines to the intermediary "frame buffer" for the 2d engine to read them. (fixed length of ??? cycles)
|
||||||
case PushScanline:
|
case PushScanline:
|
||||||
|
|
||||||
|
// reschedule events if buffer is full
|
||||||
if (scanlineswaiting >= 48)
|
if (scanlineswaiting >= 48)
|
||||||
{
|
{
|
||||||
//reschedule events if buffer is full
|
|
||||||
rasterevents[PushScanline] = rasterevents[ScanlineRead];
|
rasterevents[PushScanline] = rasterevents[ScanlineRead];
|
||||||
rasterevents[RenderStart] = /*((y >= 190) ? INT_MAX/2 :*/ rasterevents[ScanlineRead] + RastDelay;
|
// dont reschedule these events if they're done.
|
||||||
rasterevents[RenderFinal] = /*((y >= 192) ? INT_MAX/2 :*/ rasterevents[ScanlineRead];
|
rasterevents[RenderStart] = ((y > 190) ? INT_MAX/2 : rasterevents[ScanlineRead] + RastDelay);
|
||||||
|
rasterevents[RenderFinal] = ((y > 194) ? INT_MAX/2 : rasterevents[ScanlineRead]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doa)
|
leftovers = BeginPushScanline(scanlinespushed, (rasterevents[ScanlineRead] + (ScanlineReadInc*scanlineswaiting)) - rasterevents[PushScanline]);
|
||||||
{
|
scanlinesrendered--;
|
||||||
leftoversa = BeginPushScanline(scanlinespushed, 256);//(rasterevents[ScanlineRead] - ScanlineReadSpeed) - (rasterevents[PushScanline] + FinalPassLen));
|
scanlinespushed++;
|
||||||
scanlinesrendered--;
|
|
||||||
|
// schedule the finish push event if needed
|
||||||
if (leftoversa != 0)
|
if (leftovers != 0) rasterevents[PushScanlineP2] = rasterevents[ScanlineRead];
|
||||||
{
|
|
||||||
rasterevents[PushScanlineP2] = rasterevents[ScanlineRead] - ScanlineReadSpeed; // todo: fix this
|
|
||||||
fina = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
scanlineswaiting++;
|
|
||||||
scanlinespushed++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
leftoversb = BeginPushScanline(scanlinespushed, 256);//(rasterevents[ScanlineRead] + DelayBetweenReads) - (rasterevents[PushScanline] + FinalPassLen));
|
scanlineswaiting++;
|
||||||
scanlinesrendered--;
|
scanlinespushed2++;
|
||||||
|
|
||||||
if (leftoversb != 0)
|
|
||||||
{
|
|
||||||
rasterevents[PushScanlineP2] = rasterevents[ScanlineRead] + DelayBetweenReads; // todo: fix this
|
|
||||||
fina = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
scanlineswaiting++;
|
|
||||||
scanlinespushed++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scanlinesrendered <= 0)
|
if (scanlinesrendered <= 0)
|
||||||
rasterevents[PushScanline] = INT_MAX/2;
|
rasterevents[PushScanline] = INT_MAX/2; // unsched event if no scanlines are waiting to be finished
|
||||||
else
|
|
||||||
doa = !doa;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ScanlineRead:
|
|
||||||
|
|
||||||
|
// 2d engine reading scanlines from the intermediary "framebuffer"
|
||||||
|
case ScanlineRead:
|
||||||
|
|
||||||
|
// read scanline from buffer
|
||||||
ReadScanline(scanlinesread);
|
ReadScanline(scanlinesread);
|
||||||
|
// reschedule event for one scanline later
|
||||||
rasterevents[ScanlineRead] += ScanlineReadInc;
|
rasterevents[ScanlineRead] += ScanlineReadInc;
|
||||||
|
|
||||||
|
// avoid breaking seperate thread.
|
||||||
if constexpr (threaded)
|
if constexpr (threaded)
|
||||||
Platform::Semaphore_Post(Sema_ScanlineCount);
|
Platform::Semaphore_Post(Sema_ScanlineCount);
|
||||||
|
|
||||||
@ -1950,22 +1943,16 @@ void SoftRenderer::RenderPolygons(GPU& gpu, Polygon** polygons, int npolys)
|
|||||||
scanlineswaiting--;
|
scanlineswaiting--;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
// finish pushing a scanline to the buffer if it got interrupted by the read process.
|
||||||
case PushScanlineP2:
|
case PushScanlineP2:
|
||||||
|
|
||||||
if (fina)
|
FinishPushScanline(scanlinespushed2, leftovers);
|
||||||
{
|
scanlineswaiting++;
|
||||||
FinishPushScanline(yold-1, leftoversa);
|
scanlinespushed2++;
|
||||||
scanlineswaiting++;
|
|
||||||
scanlinespushed++;
|
// unschedule event if all partially pushed scanlines have been pushed
|
||||||
}
|
if (scanlinespushed2 >= scanlinespushed) rasterevents[PushScanlineP2] = INT_MAX/2;
|
||||||
else
|
|
||||||
{
|
|
||||||
FinishPushScanline(yold, leftoversb);
|
|
||||||
scanlineswaiting++;
|
|
||||||
scanlinespushed++;
|
|
||||||
}
|
|
||||||
|
|
||||||
rasterevents[PushScanlineP2] = INT_MAX/2;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user