Skip to content

Commit

Permalink
GPU: Handle immediate prims more accurately.
Browse files Browse the repository at this point in the history
This allows for lines, points, textures, and similar things.  Also
corrects offset handling.  Still some flags on VAP that seemingly don't
work, and this doesn't consider the texture flag on it.
  • Loading branch information
unknownbrackets committed Sep 6, 2022
1 parent bc3754a commit fce189f
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 11 deletions.
34 changes: 24 additions & 10 deletions GPU/GPUCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1530,6 +1530,7 @@ void GPUCommon::Execute_End(u32 op, u32 diff) {
break;

default:
FlushImm();
currentList->subIntrToken = prev & 0xFFFF;
UpdateState(GPUSTATE_DONE);
// Since we marked done, we have to restore the context now before the next list runs.
Expand Down Expand Up @@ -1651,6 +1652,7 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) {
u32 count = data & 0xFFFF;
if (count == 0)
return;
FlushImm();

// Upper bits are ignored.
GEPrimitiveType prim = static_cast<GEPrimitiveType>((data >> 16) & 7);
Expand Down Expand Up @@ -2379,13 +2381,17 @@ void GPUCommon::Execute_ImmVertexAlphaPrim(u32 op, u32 diff) {
return;
}

int prim = (op >> 8) & 0x7;
if (prim != GE_PRIM_KEEP_PREVIOUS) {
// Flush before changing the prim type. Only continue can be used to continue a prim.
FlushImm();
}

TransformedVertex &v = immBuffer_[immCount_++];

// Formula deduced from ThrillVille's clear.
int offsetX = gstate.getOffsetX16();
int offsetY = gstate.getOffsetY16();
v.x = ((gstate.imm_vscx & 0xFFFFFF) - offsetX) / 16.0f;
v.y = ((gstate.imm_vscy & 0xFFFFFF) - offsetY) / 16.0f;
v.x = ((gstate.imm_vscx & 0xFFFF) - 0x8000) / 16.0f;
v.y = ((gstate.imm_vscy & 0xFFFF) - 0x8000) / 16.0f;
v.z = gstate.imm_vscz & 0xFFFF;
v.pos_w = 1.0f;
v.u = getFloat24(gstate.imm_vtcs);
Expand All @@ -2394,26 +2400,29 @@ void GPUCommon::Execute_ImmVertexAlphaPrim(u32 op, u32 diff) {
v.color0_32 = (gstate.imm_cv & 0xFFFFFF) | (gstate.imm_ap << 24);
v.fog = 0.0f; // we have no information about the scale here
v.color1_32 = gstate.imm_scv & 0xFFFFFF;
int prim = (op >> 8) & 0x7;
if (prim != GE_PRIM_KEEP_PREVIOUS) {
immPrim_ = (GEPrimitiveType)prim;
} else if (prim == GE_PRIM_KEEP_PREVIOUS && immCount_ == 2) {
} else if (prim == GE_PRIM_KEEP_PREVIOUS && immPrim_ != GE_PRIM_INVALID) {
static constexpr int flushPrimCount[] = { 1, 2, 0, 3, 0, 0, 2, 0 };
// Instead of finding a proper point to flush, we just emit a full rectangle every time one
// is finished.
FlushImm();
// Need to reset immCount_ here. If we do it in FlushImm it could get skipped by gstate_c.skipDrawReason.
immCount_ = 0;
if (immCount_ == flushPrimCount[immPrim_ & 7])
FlushImm();
} else {
ERROR_LOG_REPORT_ONCE(imm_draw_prim, G3D, "Immediate draw: Unexpected primitive %d at count %d", prim, immCount_);
}
}

void GPUCommon::FlushImm() {
if (immCount_ == 0 || immPrim_ == GE_PRIM_INVALID)
return;

SetDrawType(DRAW_PRIM, immPrim_);
if (framebufferManager_)
framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
// No idea how many cycles to skip, heh.
immCount_ = 0;
return;
}
UpdateUVScaleOffset();
Expand All @@ -2423,23 +2432,28 @@ void GPUCommon::FlushImm() {
// through vertices.
// Since the only known use is Thrillville and it only uses it to clear, we just use color and pos.
struct ImmVertex {
float uv[2];
uint32_t color;
float xyz[3];
};
ImmVertex temp[MAX_IMMBUFFER_SIZE];
for (int i = 0; i < immCount_; i++) {
// Since we're sending through, scale back up to w/h.
temp[i].uv[0] = immBuffer_[i].u * gstate.getTextureWidth(0);
temp[i].uv[1] = immBuffer_[i].v * gstate.getTextureHeight(0);
temp[i].color = immBuffer_[i].color0_32;
temp[i].xyz[0] = immBuffer_[i].pos[0];
temp[i].xyz[1] = immBuffer_[i].pos[1];
temp[i].xyz[2] = immBuffer_[i].pos[2];
}
int vtype = GE_VTYPE_POS_FLOAT | GE_VTYPE_COL_8888 | GE_VTYPE_THROUGH;
int vtype = GE_VTYPE_TC_FLOAT | GE_VTYPE_POS_FLOAT | GE_VTYPE_COL_8888 | GE_VTYPE_THROUGH;

int bytesRead;
uint32_t vertTypeID = GetVertTypeID(vtype, 0);
drawEngineCommon_->DispatchSubmitImm(temp, nullptr, immPrim_, immCount_, vertTypeID, gstate.getCullMode(), &bytesRead);
// TOOD: In the future, make a special path for these.
// drawEngineCommon_->DispatchSubmitImm(immBuffer_, immCount_);
immCount_ = 0;
}

void GPUCommon::ExecuteOp(u32 op, u32 diff) {
Expand Down
2 changes: 1 addition & 1 deletion GPU/GPUCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ class GPUCommon : public GPUInterface, public GPUDebugInterface {

TransformedVertex immBuffer_[MAX_IMMBUFFER_SIZE];
int immCount_ = 0;
GEPrimitiveType immPrim_;
GEPrimitiveType immPrim_ = GE_PRIM_INVALID;

std::string reportingPrimaryInfo_;
std::string reportingFullInfo_;
Expand Down

0 comments on commit fce189f

Please sign in to comment.