Fix POLY_XLU_DISP overflow by making gfx buffers 10x larger, added error reporting when gfx buffers overflow
This commit is contained in:
parent
e97242af2e
commit
5a1dbb96f4
|
@ -2,18 +2,7 @@
|
|||
#include "fault.h"
|
||||
#include "transform_ids.h"
|
||||
|
||||
// Start after G_EX_ID_IGNORE to avoid assigning it to a group.
|
||||
u32 next_actor_transform = ACTOR_TRANSFORM_ID_START;
|
||||
|
||||
// Use 32 bits of compiler-inserted padding to hold the actor's transform ID.
|
||||
// 0x22 between halfDaysBits and world
|
||||
#define actorIdByte0(actor) ((u8*)(&(actor)->halfDaysBits))[2]
|
||||
// 0x23 between halfDaysBits and world
|
||||
#define actorIdByte1(actor) ((u8*)(&(actor)->halfDaysBits))[3]
|
||||
// 0x3A between audioFlags and focus
|
||||
#define actorIdByte2(actor) ((u8*)(&(actor)->audioFlags))[1]
|
||||
// 0x3B between audioFlags and focus
|
||||
#define actorIdByte3(actor) ((u8*)(&(actor)->audioFlags))[2]
|
||||
u16 next_actor_transform = 0;
|
||||
|
||||
extern FaultClient sActorFaultClient;
|
||||
Actor* Actor_Delete(ActorContext* actorCtx, Actor* actor, PlayState* play);
|
||||
|
@ -45,7 +34,7 @@ void Actor_CleanupContext(ActorContext* actorCtx, PlayState* play) {
|
|||
}
|
||||
|
||||
// @recomp Reset the actor transform IDs as all actors have been deleted.
|
||||
next_actor_transform = ACTOR_TRANSFORM_ID_START;
|
||||
next_actor_transform = 0;
|
||||
|
||||
Play_SaveCycleSceneFlags(&play->state);
|
||||
ActorOverlayTable_Cleanup();
|
||||
|
@ -53,20 +42,7 @@ void Actor_CleanupContext(ActorContext* actorCtx, PlayState* play) {
|
|||
|
||||
u32 create_actor_transform_id() {
|
||||
u32 ret = next_actor_transform;
|
||||
next_actor_transform += ACTOR_TRANSFORM_ID_COUNT;
|
||||
|
||||
// If the actor transform ID has overflowed, wrap back to the starting ID.
|
||||
if (next_actor_transform < ACTOR_TRANSFORM_ID_START) {
|
||||
next_actor_transform = ACTOR_TRANSFORM_ID_START;
|
||||
// Pick a new ID to make sure the actor has a valid range of IDs to use.
|
||||
ret = next_actor_transform;
|
||||
next_actor_transform += ACTOR_TRANSFORM_ID_COUNT;
|
||||
}
|
||||
|
||||
// Skip ranges that include the special transform IDs.
|
||||
while (G_EX_ID_IGNORE - next_actor_transform < ACTOR_TRANSFORM_ID_COUNT || G_EX_ID_AUTO - next_actor_transform < ACTOR_TRANSFORM_ID_COUNT) {
|
||||
next_actor_transform += ACTOR_TRANSFORM_ID_COUNT;
|
||||
}
|
||||
next_actor_transform++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -100,19 +76,13 @@ void Actor_Init(Actor* actor, PlayState* play) {
|
|||
// @recomp Pick a transform ID for this actor and encode it into struct padding
|
||||
u32 cur_transform_id = create_actor_transform_id();
|
||||
actorIdByte0(actor) = (cur_transform_id >> 0) & 0xFF;
|
||||
actorIdByte1(actor) = (cur_transform_id >> 8) & 0xFF;
|
||||
actorIdByte2(actor) = (cur_transform_id >> 16) & 0xFF;
|
||||
actorIdByte3(actor) = (cur_transform_id >> 24) & 0xFF;
|
||||
actorIdByte1(actor) = (cur_transform_id >> 8) & 0xFF;;
|
||||
}
|
||||
|
||||
// Extract the transform ID for this actor, add the limb index and write that as the matrix group to POLY_OPA_DISP.
|
||||
Gfx* push_limb_matrix_group(Gfx* dlist, Actor* actor, u32 limb_index) {
|
||||
if (actor != NULL) {
|
||||
u32 cur_transform_id =
|
||||
(actorIdByte0(actor) << 0) |
|
||||
(actorIdByte1(actor) << 8) |
|
||||
(actorIdByte2(actor) << 16) |
|
||||
(actorIdByte3(actor) << 24);
|
||||
u32 cur_transform_id = actor_transform_id(actor);
|
||||
gEXMatrixGroup(dlist++, cur_transform_id + limb_index, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_SKIP, G_EX_ORDER_LINEAR);
|
||||
}
|
||||
return dlist;
|
||||
|
@ -121,11 +91,7 @@ Gfx* push_limb_matrix_group(Gfx* dlist, Actor* actor, u32 limb_index) {
|
|||
// Extract the transform ID for this actor, add the limb index and post-limb offset and write that as the matrix group to POLY_OPA_DISP.
|
||||
Gfx* push_post_limb_matrix_group(Gfx* dlist, Actor* actor, u32 limb_index) {
|
||||
if (actor != NULL) {
|
||||
u32 cur_transform_id =
|
||||
(actorIdByte0(actor) << 0) |
|
||||
(actorIdByte1(actor) << 8) |
|
||||
(actorIdByte2(actor) << 16) |
|
||||
(actorIdByte3(actor) << 24);
|
||||
u32 cur_transform_id = actor_transform_id(actor);
|
||||
gEXMatrixGroup(dlist++, cur_transform_id + limb_index + ACTOR_TRANSFORM_LIMB_COUNT, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_SKIP, G_EX_ORDER_LINEAR);
|
||||
}
|
||||
return dlist;
|
||||
|
@ -134,11 +100,7 @@ Gfx* push_post_limb_matrix_group(Gfx* dlist, Actor* actor, u32 limb_index) {
|
|||
// Extract the transform ID for this actor, add the limb index and write that as the matrix group to POLY_OPA_DISP.
|
||||
Gfx* push_skin_limb_matrix_group(Gfx* dlist, Actor* actor, u32 limb_index) {
|
||||
if (actor != NULL) {
|
||||
u32 cur_transform_id =
|
||||
(actorIdByte0(actor) << 0) |
|
||||
(actorIdByte1(actor) << 8) |
|
||||
(actorIdByte2(actor) << 16) |
|
||||
(actorIdByte3(actor) << 24);
|
||||
u32 cur_transform_id = actor_transform_id(actor);
|
||||
gEXMatrixGroup(dlist++, cur_transform_id + limb_index, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_ORDER_LINEAR);
|
||||
}
|
||||
return dlist;
|
||||
|
@ -1193,11 +1155,7 @@ void tag_actor_displaylists(Actor* actor, PlayState* play, Gfx* opa_start, Gfx*
|
|||
|
||||
// If the actor wrote at least one matrix in total and at most one matrix to each list, tag that matrix with the actor's id.
|
||||
if ((opa_matrices == 1 || xlu_matrices == 1) && opa_matrices <= 1 && xlu_matrices <= 1) {
|
||||
u32 cur_transform_id =
|
||||
(actorIdByte0(actor) << 0) |
|
||||
(actorIdByte1(actor) << 8) |
|
||||
(actorIdByte2(actor) << 16) |
|
||||
(actorIdByte3(actor) << 24);
|
||||
u32 cur_transform_id = actor_transform_id(actor);
|
||||
|
||||
if (opa_matrices == 1) {
|
||||
// Fill in the slot that was reserved for a transform id.
|
||||
|
@ -1207,13 +1165,13 @@ void tag_actor_displaylists(Actor* actor, PlayState* play, Gfx* opa_start, Gfx*
|
|||
gEXPopMatrixGroup(POLY_OPA_DISP++);
|
||||
}
|
||||
|
||||
// if (xlu_matrices == 1) {
|
||||
// // Fill in the slot that was reserved for a transform id.
|
||||
// gEXMatrixGroup(xlu_start, cur_transform_id + 1, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_SKIP, G_EX_ORDER_LINEAR);
|
||||
if (xlu_matrices == 1) {
|
||||
// Fill in the slot that was reserved for a transform id.
|
||||
gEXMatrixGroup(xlu_start, cur_transform_id + 1, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_SKIP, G_EX_ORDER_LINEAR);
|
||||
|
||||
// // Pop the matrix groups.
|
||||
// gEXPopMatrixGroup(POLY_XLU_DISP++);
|
||||
// }
|
||||
// Pop the matrix groups.
|
||||
gEXPopMatrixGroup(POLY_XLU_DISP++);
|
||||
}
|
||||
}
|
||||
|
||||
CLOSE_DISPS();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
RAMBASE = 0x80800100; /* Used to hold any new symbols */
|
||||
|
||||
MEMORY {
|
||||
extram : ORIGIN = RAMBASE, LENGTH = 1M
|
||||
extram : ORIGIN = RAMBASE, LENGTH = 8M
|
||||
rom : ORIGIN = 0, LENGTH = 1M
|
||||
}
|
||||
|
||||
|
|
|
@ -14,4 +14,22 @@
|
|||
#define ACTOR_TRANSFORM_ID_COUNT (ACTOR_TRANSFORM_LIMB_COUNT * 2) // One ID for each limb and another for each post-draw
|
||||
#define ACTOR_TRANSFORM_ID_START 0x1000000U
|
||||
|
||||
// Use 16 bits of compiler-inserted padding to hold the actor's transform ID.
|
||||
// 0x22 between halfDaysBits and world
|
||||
#define actorIdByte0(actor) ((u8*)(actor))[0x22]
|
||||
// 0x23 between halfDaysBits and world
|
||||
#define actorIdByte1(actor) ((u8*)(actor))[0x23]
|
||||
|
||||
// Other unused padding:
|
||||
// 0x3A between audioFlags and focus
|
||||
// 0x3B between audioFlags and focus
|
||||
|
||||
static inline u32 actor_transform_id(Actor* actor) {
|
||||
u32 actor_id =
|
||||
(actorIdByte0(actor) << 0) |
|
||||
(actorIdByte1(actor) << 8);
|
||||
|
||||
return (actor_id * ACTOR_TRANSFORM_ID_COUNT) + ACTOR_TRANSFORM_ID_START;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,9 +8,22 @@ s32 margin_reduction = 8;
|
|||
|
||||
extern s32 gFramerateDivisor;
|
||||
|
||||
// Modified to enable RT64 extended GBI mode
|
||||
// 10 times bigger than the game's normal buffers.
|
||||
typedef struct {
|
||||
GfxMasterList master;
|
||||
Gfx polyXluBuffer[0x8000];
|
||||
Gfx overlayBuffer[0x4000];
|
||||
Gfx workBuffer[0x400];
|
||||
Gfx debugBuffer[0x400];
|
||||
Gfx polyOpaBuffer[0x33800];
|
||||
} BiggerGfxPool;
|
||||
|
||||
BiggerGfxPool gBiggerGfxPools[2];
|
||||
|
||||
// @recomp Use the bigger gfx pools and enable RT64 extended GBI mode.
|
||||
void Graph_SetNextGfxPool(GraphicsContext* gfxCtx) {
|
||||
GfxPool* pool = &gGfxPools[gfxCtx->gfxPoolIdx % 2];
|
||||
BiggerGfxPool* bigger_pool = &gBiggerGfxPools[gfxCtx->gfxPoolIdx % 2];
|
||||
|
||||
gGfxMasterDL = &pool->master;
|
||||
gSegments[0x0E] = (uintptr_t)gGfxMasterDL;
|
||||
|
@ -18,29 +31,29 @@ void Graph_SetNextGfxPool(GraphicsContext* gfxCtx) {
|
|||
pool->headMagic = GFXPOOL_HEAD_MAGIC;
|
||||
pool->tailMagic = GFXPOOL_TAIL_MAGIC;
|
||||
|
||||
Graph_InitTHGA(&gfxCtx->polyOpa, pool->polyOpaBuffer, sizeof(pool->polyOpaBuffer));
|
||||
Graph_InitTHGA(&gfxCtx->polyXlu, pool->polyXluBuffer, sizeof(pool->polyXluBuffer));
|
||||
Graph_InitTHGA(&gfxCtx->overlay, pool->overlayBuffer, sizeof(pool->overlayBuffer));
|
||||
Graph_InitTHGA(&gfxCtx->work, pool->workBuffer, sizeof(pool->workBuffer));
|
||||
Graph_InitTHGA(&gfxCtx->debug, pool->debugBuffer, sizeof(pool->debugBuffer));
|
||||
Graph_InitTHGA(&gfxCtx->polyOpa, bigger_pool->polyOpaBuffer, sizeof(bigger_pool->polyOpaBuffer));
|
||||
Graph_InitTHGA(&gfxCtx->polyXlu, bigger_pool->polyXluBuffer, sizeof(bigger_pool->polyXluBuffer));
|
||||
Graph_InitTHGA(&gfxCtx->overlay, bigger_pool->overlayBuffer, sizeof(bigger_pool->overlayBuffer));
|
||||
Graph_InitTHGA(&gfxCtx->work, bigger_pool->workBuffer, sizeof(bigger_pool->workBuffer));
|
||||
Graph_InitTHGA(&gfxCtx->debug, bigger_pool->debugBuffer, sizeof(bigger_pool->debugBuffer));
|
||||
|
||||
gfxCtx->polyOpaBuffer = pool->polyOpaBuffer;
|
||||
gfxCtx->polyXluBuffer = pool->polyXluBuffer;
|
||||
gfxCtx->overlayBuffer = pool->overlayBuffer;
|
||||
gfxCtx->workBuffer = pool->workBuffer;
|
||||
gfxCtx->debugBuffer = pool->debugBuffer;
|
||||
gfxCtx->polyOpaBuffer = bigger_pool->polyOpaBuffer;
|
||||
gfxCtx->polyXluBuffer = bigger_pool->polyXluBuffer;
|
||||
gfxCtx->overlayBuffer = bigger_pool->overlayBuffer;
|
||||
gfxCtx->workBuffer = bigger_pool->workBuffer;
|
||||
gfxCtx->debugBuffer = bigger_pool->debugBuffer;
|
||||
|
||||
gfxCtx->curFrameBuffer = SysCfb_GetFramebuffer(gfxCtx->framebufferIndex % 2);
|
||||
gSegments[0x0F] = (uintptr_t)gfxCtx->curFrameBuffer;
|
||||
|
||||
gfxCtx->zbuffer = SysCfb_GetZBuffer();
|
||||
|
||||
gSPBranchList(&gGfxMasterDL->disps[0], pool->polyOpaBuffer);
|
||||
gSPBranchList(&gGfxMasterDL->disps[1], pool->polyXluBuffer);
|
||||
gSPBranchList(&gGfxMasterDL->disps[2], pool->overlayBuffer);
|
||||
gSPBranchList(&gGfxMasterDL->disps[3], pool->workBuffer);
|
||||
gSPBranchList(&gGfxMasterDL->disps[0], bigger_pool->polyOpaBuffer);
|
||||
gSPBranchList(&gGfxMasterDL->disps[1], bigger_pool->polyXluBuffer);
|
||||
gSPBranchList(&gGfxMasterDL->disps[2], bigger_pool->overlayBuffer);
|
||||
gSPBranchList(&gGfxMasterDL->disps[3], bigger_pool->workBuffer);
|
||||
gSPEndDisplayList(&gGfxMasterDL->disps[4]);
|
||||
gSPBranchList(&gGfxMasterDL->debugDisp[0], pool->debugBuffer);
|
||||
gSPBranchList(&gGfxMasterDL->debugDisp[0], bigger_pool->debugBuffer);
|
||||
|
||||
// @recomp Enable RT64 extended GBI mode and set the current framerate
|
||||
OPEN_DISPS(gfxCtx);
|
||||
|
@ -50,6 +63,113 @@ void Graph_SetNextGfxPool(GraphicsContext* gfxCtx) {
|
|||
CLOSE_DISPS(gfxCtx);
|
||||
}
|
||||
|
||||
void recomp_crash(const char* err) {
|
||||
recomp_printf("%s\n", err);
|
||||
// TODO open a message box instead of a hard crash
|
||||
*(volatile int*)0 = 0;
|
||||
}
|
||||
|
||||
extern volatile OSTime gRSPGfxTimeTotal;
|
||||
extern volatile OSTime gRSPGfxTimeAcc;
|
||||
extern volatile OSTime gRSPAudioTimeTotal;
|
||||
extern volatile OSTime gRSPAudioTimeAcc;
|
||||
extern volatile OSTime gRDPTimeTotal;
|
||||
extern volatile OSTime gRDPTimeAcc;
|
||||
extern OSTime sGraphPrevUpdateEndTime;
|
||||
extern volatile OSTime gGraphUpdatePeriod;
|
||||
|
||||
// @recomp Modified to report errors instead of skipping frames.
|
||||
/**
|
||||
* Run the game state logic, then finalize the gfx buffer
|
||||
* and run the graphics task for this frame.
|
||||
*/
|
||||
void Graph_ExecuteAndDraw(GraphicsContext* gfxCtx, GameState* gameState) {
|
||||
u32 problem;
|
||||
|
||||
gameState->unk_A3 = 0;
|
||||
Graph_SetNextGfxPool(gfxCtx);
|
||||
|
||||
GameState_Update(gameState);
|
||||
|
||||
OPEN_DISPS(gfxCtx);
|
||||
|
||||
gSPEndDisplayList(WORK_DISP++);
|
||||
gSPEndDisplayList(POLY_OPA_DISP++);
|
||||
gSPEndDisplayList(POLY_XLU_DISP++);
|
||||
gSPEndDisplayList(OVERLAY_DISP++);
|
||||
gSPEndDisplayList(DEBUG_DISP++);
|
||||
|
||||
CLOSE_DISPS(gfxCtx);
|
||||
|
||||
{
|
||||
Gfx* gfx = gGfxMasterDL->taskStart;
|
||||
|
||||
gSPSegment(gfx++, 0x0E, gGfxMasterDL);
|
||||
gSPDisplayList(gfx++, &D_0E000000.disps[3]);
|
||||
gSPDisplayList(gfx++, &D_0E000000.disps[0]);
|
||||
gSPDisplayList(gfx++, &D_0E000000.disps[1]);
|
||||
gSPDisplayList(gfx++, &D_0E000000.disps[2]);
|
||||
gSPDisplayList(gfx++, &D_0E000000.debugDisp[0]);
|
||||
|
||||
gDPPipeSync(gfx++);
|
||||
gDPFullSync(gfx++);
|
||||
gSPEndDisplayList(gfx++);
|
||||
}
|
||||
|
||||
problem = false;
|
||||
|
||||
// @recomp Patch all error conditions to print to console and crash the application.
|
||||
{
|
||||
GfxPool* pool = &gGfxPools[gfxCtx->gfxPoolIdx % 2];
|
||||
|
||||
if (pool->headMagic != GFXPOOL_HEAD_MAGIC) {
|
||||
recomp_crash("GfxPool headMagic integrity check failed!");
|
||||
}
|
||||
if (pool->tailMagic != GFXPOOL_TAIL_MAGIC) {
|
||||
recomp_crash("GfxPool tailMagic integrity check failed!");
|
||||
}
|
||||
}
|
||||
|
||||
if (THGA_IsCrash(&gfxCtx->polyOpa)) {
|
||||
recomp_crash("gfxCtx->polyOpa overflow!");
|
||||
}
|
||||
if (THGA_IsCrash(&gfxCtx->polyXlu)) {
|
||||
recomp_crash("gfxCtx->polyXlu overflow!");
|
||||
}
|
||||
if (THGA_IsCrash(&gfxCtx->overlay)) {
|
||||
recomp_crash("gfxCtx->overlay overflow!");
|
||||
}
|
||||
if (THGA_IsCrash(&gfxCtx->work)) {
|
||||
recomp_crash("gfxCtx->work overflow!");
|
||||
}
|
||||
if (THGA_IsCrash(&gfxCtx->debug)) {
|
||||
recomp_crash("gfxCtx->debug overflow!");
|
||||
}
|
||||
|
||||
if (!problem) {
|
||||
Graph_TaskSet00(gfxCtx, gameState);
|
||||
gfxCtx->gfxPoolIdx++;
|
||||
gfxCtx->framebufferIndex++;
|
||||
}
|
||||
|
||||
{
|
||||
OSTime time = osGetTime();
|
||||
|
||||
gRSPGfxTimeTotal = gRSPGfxTimeAcc;
|
||||
gRSPAudioTimeTotal = gRSPAudioTimeAcc;
|
||||
gRDPTimeTotal = gRDPTimeAcc;
|
||||
gRSPGfxTimeAcc = 0;
|
||||
gRSPAudioTimeAcc = 0;
|
||||
gRDPTimeAcc = 0;
|
||||
|
||||
if (sGraphPrevUpdateEndTime != 0) {
|
||||
gGraphUpdatePeriod = time - sGraphPrevUpdateEndTime;
|
||||
}
|
||||
sGraphPrevUpdateEndTime = time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef enum {
|
||||
/* 0 */ PICTO_BOX_STATE_OFF, // Not using the pictograph
|
||||
/* 1 */ PICTO_BOX_STATE_LENS, // Looking through the lens of the pictograph
|
||||
|
|
Loading…
Reference in New Issue