softgpu: Support fog and color1 on imm verts.

This commit is contained in:
Unknown W. Brackets 2022-09-17 19:42:41 -07:00
parent 35ba01e01f
commit 596b07bd2e
9 changed files with 109 additions and 43 deletions

View File

@ -215,6 +215,9 @@ void DrawEngineCommon::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex
int vtype = GE_VTYPE_TC_FLOAT | GE_VTYPE_POS_FLOAT | GE_VTYPE_COL_8888 | GE_VTYPE_THROUGH;
// TODO: Handle fog and secondary color somehow?
if (gstate.isFogEnabled()) {
WARN_LOG_REPORT_ONCE(geimmfog, G3D, "Imm vertex used fog");
}
if (color1Used != 0 && gstate.isUsingSecondaryColor()) {
WARN_LOG_REPORT_ONCE(geimmcolor1, G3D, "Imm vertex used secondary color");
}

View File

@ -2447,21 +2447,22 @@ void GPUCommon::FlushImm() {
int cullMode = (immFlags_ & GE_IMM_CULLFACE) != 0 ? 1 : 0;
bool texturing = (immFlags_ & GE_IMM_TEXTURE) != 0;
bool prevTexturing = gstate.isTextureMapEnabled();
bool fog = (immFlags_ & GE_IMM_FOG) != 0;
bool prevFog = gstate.isFogEnabled();
bool dither = (immFlags_ & GE_IMM_DITHER) != 0;
bool prevDither = gstate.isDitherEnabled();
if ((immFlags_ & GE_IMM_CLIPMASK) != 0) {
WARN_LOG_REPORT_ONCE(geimmclipvalue, G3D, "Imm vertex used clip value, flags=%06x", immFlags_);
} else if ((immFlags_ & GE_IMM_FOG) != 0) {
WARN_LOG_REPORT_ONCE(geimmfog, G3D, "Imm vertex used fog, flags=%06x", immFlags_);
}
if (texturing != prevTexturing || cullEnable != prevCullEnable || dither != prevDither || prevShading != shading) {
if (texturing != prevTexturing || cullEnable != prevCullEnable || dither != prevDither || prevShading != shading || prevFog != fog) {
DispatchFlush();
gstate.antiAliasEnable = (GE_CMD_ANTIALIASENABLE << 24) | (int)antialias;
gstate.shademodel = (GE_CMD_SHADEMODE << 24) | (int)shading;
gstate.cullfaceEnable = (GE_CMD_CULLFACEENABLE << 24) | (int)cullEnable;
gstate.textureMapEnable = (GE_CMD_TEXTUREMAPENABLE << 24) | (int)texturing;
gstate.fogEnable = (GE_CMD_FOGENABLE << 24) | (int)fog;
gstate.ditherEnable = (GE_CMD_DITHERENABLE << 24) | (int)dither;
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_RASTER_STATE);
}
@ -2473,6 +2474,7 @@ void GPUCommon::FlushImm() {
gstate.shademodel = (GE_CMD_SHADEMODE << 24) | (int)prevShading;
gstate.cullfaceEnable = (GE_CMD_CULLFACEENABLE << 24) | (int)prevCullEnable;
gstate.textureMapEnable = (GE_CMD_TEXTUREMAPENABLE << 24) | (int)prevTexturing;
gstate.fogEnable = (GE_CMD_FOGENABLE << 24) | (int)prevFog;
gstate.ditherEnable = (GE_CMD_DITHERENABLE << 24) | (int)prevDither;
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_RASTER_STATE);
}

View File

@ -167,7 +167,7 @@ void BinManager::UpdateState(bool throughMode) {
if (states_.Full())
Flush("states");
stateIndex_ = (uint16_t)states_.Push(RasterizerState());
ComputeRasterizerState(&states_[stateIndex_], throughMode);
ComputeRasterizerState(&states_[stateIndex_]);
states_[stateIndex_].samplerID.cached.clut = cluts_[clutIndex_].readable;
ClearDirty(SoftDirty::PIXEL_ALL | SoftDirty::SAMPLER_ALL | SoftDirty::RAST_ALL);

View File

@ -48,11 +48,11 @@ static inline PixelBlendFactor OptimizeAlphaFactor(uint32_t color) {
return PixelBlendFactor::FIX;
}
void ComputePixelFuncID(PixelFuncID *id, bool throughMode) {
void ComputePixelFuncID(PixelFuncID *id) {
id->fullKey = 0;
// TODO: Could this be minz > 0x0000 || maxz < 0xFFFF? Maybe unsafe, depending on verts...
id->applyDepthRange = !throughMode;
id->applyDepthRange = !gstate.isModeThrough();
// Dither happens even in clear mode.
id->dithering = gstate.isDitherEnabled();
id->fbFormat = gstate.FrameBufFormat();
@ -169,7 +169,7 @@ void ComputePixelFuncID(PixelFuncID *id, bool throughMode) {
}
id->applyLogicOp = gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY;
id->applyFog = gstate.isFogEnabled() && !throughMode;
id->applyFog = gstate.isFogEnabled() && !gstate.isModeThrough();
id->earlyZChecks = id->DepthTestFunc() != GE_COMP_ALWAYS;
if (id->stencilTest && id->earlyZChecks) {

View File

@ -244,7 +244,7 @@ struct hash<SamplerID> {
};
void ComputePixelFuncID(PixelFuncID *id, bool throughMode);
void ComputePixelFuncID(PixelFuncID *id);
std::string DescribePixelFuncID(const PixelFuncID &id);
void ComputeSamplerID(SamplerID *id);

View File

@ -93,8 +93,8 @@ static inline Vec4<float> Interpolate(const float &c0, const float &c1, const fl
return Interpolate(c0, c1, c2, w0.Cast<float>(), w1.Cast<float>(), w2.Cast<float>(), wsum_recip);
}
void ComputeRasterizerState(RasterizerState *state, bool throughMode) {
ComputePixelFuncID(&state->pixelID, throughMode);
void ComputeRasterizerState(RasterizerState *state) {
ComputePixelFuncID(&state->pixelID);
state->drawPixel = Rasterizer::GetSingleFunc(state->pixelID);
state->enableTextures = gstate.isTextureMapEnabled() && !state->pixelID.clearMode;
@ -132,7 +132,7 @@ void ComputeRasterizerState(RasterizerState *state, bool throughMode) {
}
state->shadeGouraud = gstate.getShadeMode() == GE_SHADE_GOURAUD;
state->throughMode = throughMode;
state->throughMode = gstate.isModeThrough();
state->antialiasLines = gstate.isAntiAliasEnabled();
#if defined(SOFTGPU_MEMORY_TAGGING_DETAILED) || defined(SOFTGPU_MEMORY_TAGGING_BASIC)

View File

@ -65,7 +65,7 @@ struct RasterizerState {
}
};
void ComputeRasterizerState(RasterizerState *state, bool throughMode);
void ComputeRasterizerState(RasterizerState *state);
// Draws a triangle if its vertices are specified in counter-clockwise order
void DrawTriangle(const VertexData &v0, const VertexData &v1, const VertexData &v2, const BinCoords &range, const RasterizerState &state);

View File

@ -71,46 +71,64 @@ void SoftwareDrawEngine::DispatchSubmitPrim(const void *verts, const void *inds,
}
void SoftwareDrawEngine::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex *buffer, int vertexCount, int cullMode) {
// TODO: Handle fog and secondary color somehow?
int vtype = GE_VTYPE_TC_FLOAT | GE_VTYPE_POS_FLOAT | GE_VTYPE_COL_8888 | GE_VTYPE_THROUGH;
uint32_t vertTypeID = GetVertTypeID(vtype, 0);
uint32_t vertTypeID = GetVertTypeID(gstate.vertType, gstate.getUVGenMode());
int flipCull = cullMode != gstate.getCullMode() ? 1 : 0;
// TODO: For now, just setting all dirty.
transformUnit.SetDirty(SoftDirty(-1));
gstate.cullmode ^= flipCull;
// Instead of plumbing through properly (we'd need to inject these pretransformed vertices in the middle
// of SoftwareTransform(), which would take a lot of refactoring), we'll cheat and just turn these into
// 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];
};
std::vector<ImmVertex> temp;
temp.resize(vertexCount);
uint32_t color1Used = 0;
// TODO: This is a bit ugly. Should bypass when clipping...
uint32_t xScale = gstate.viewportxscale;
uint32_t xCenter = gstate.viewportxcenter;
uint32_t yScale = gstate.viewportyscale;
uint32_t yCenter = gstate.viewportycenter;
uint32_t zScale = gstate.viewportzscale;
uint32_t zCenter = gstate.viewportzcenter;
// Force scale to 1 and center to zero.
gstate.viewportxscale = (GE_CMD_VIEWPORTXSCALE << 24) | 0x3F8000;
gstate.viewportxcenter = (GE_CMD_VIEWPORTXCENTER << 24) | 0x000000;
gstate.viewportyscale = (GE_CMD_VIEWPORTYSCALE << 24) | 0x3F8000;
gstate.viewportycenter = (GE_CMD_VIEWPORTYCENTER << 24) | 0x000000;
// Z we scale to 65535 for neg z clipping.
gstate.viewportzscale = (GE_CMD_VIEWPORTZSCALE << 24) | 0x477FFF;
gstate.viewportzcenter = (GE_CMD_VIEWPORTZCENTER << 24) | 0x000000;
// Before we start, submit 0 prims to reset the prev prim type.
// Following submits will always be KEEP_PREVIOUS.
transformUnit.SubmitPrimitive(nullptr, nullptr, prim, 0, vertTypeID, nullptr, this);
for (int i = 0; i < vertexCount; i++) {
// Since we're sending through, scale back up to w/h.
temp[i].uv[0] = buffer[i].u * gstate.getTextureWidth(0);
temp[i].uv[1] = buffer[i].v * gstate.getTextureHeight(0);
temp[i].color = buffer[i].color0_32;
temp[i].xyz[0] = buffer[i].pos[0];
temp[i].xyz[1] = buffer[i].pos[1];
temp[i].xyz[2] = buffer[i].pos[2];
color1Used |= buffer[i].color1_32;
VertexData vert;
vert.clippos = ClipCoords(buffer[i].pos);
vert.texturecoords.x = buffer[i].u;
vert.texturecoords.y = buffer[i].v;
if (gstate.isModeThrough()) {
vert.texturecoords.x *= gstate.getTextureWidth(0);
vert.texturecoords.y *= gstate.getTextureHeight(0);
} else {
vert.clippos.z *= 1.0f / 65535.0f;
}
vert.color0 = buffer[i].color0_32;
vert.color1 = gstate.isUsingSecondaryColor() ? buffer[i].color1_32 : 0;
vert.fogdepth = buffer[i].fog;
vert.screenpos.x = (int)(buffer[i].x * 16.0f);
vert.screenpos.y = (int)(buffer[i].y * 16.0f);
vert.screenpos.z = (u16)(u32)buffer[i].z;
transformUnit.SubmitImmVertex(vert, this);
}
if (color1Used != 0 && gstate.isUsingSecondaryColor()) {
WARN_LOG_REPORT_ONCE(geimmcolor1, G3D, "Imm vertex used secondary color");
}
transformUnit.SubmitPrimitive(&temp[0], nullptr, prim, vertexCount, vertTypeID, nullptr, this);
gstate.viewportxscale = xScale;
gstate.viewportxcenter = xCenter;
gstate.viewportyscale = yScale;
gstate.viewportycenter = yCenter;
gstate.viewportzscale = zScale;
gstate.viewportzcenter = zCenter;
gstate.cullmode ^= flipCull;
// TODO: Should really clear, but the vertex type is faked so things might need resetting...
// TODO: Should really clear, but a bunch of values are forced so we this is safest.
transformUnit.SetDirty(SoftDirty(-1));
}
@ -492,12 +510,13 @@ void TransformUnit::SubmitPrimitive(const void* vertices, const void* indices, G
return;
u16 index_lower_bound = 0;
u16 index_upper_bound = vertex_count - 1;
u16 index_upper_bound = vertex_count == 0 ? 0 : vertex_count - 1;
IndexConverter ConvertIndex(vertex_type, indices);
if (indices)
GetIndexBounds(indices, vertex_count, vertex_type, &index_lower_bound, &index_upper_bound);
vdecoder.DecodeVerts(decoded_, vertices, index_lower_bound, index_upper_bound);
if (vertex_count != 0)
vdecoder.DecodeVerts(decoded_, vertices, index_lower_bound, index_upper_bound);
VertexReader vreader(decoded_, vtxfmt, vertex_type);
@ -786,6 +805,47 @@ void TransformUnit::SubmitPrimitive(const void* vertices, const void* indices, G
}
}
void TransformUnit::SubmitImmVertex(const VertexData &vert, SoftwareDrawEngine *drawEngine) {
// Where we put it is different for STRIP/FAN types.
switch (prev_prim_) {
case GE_PRIM_POINTS:
case GE_PRIM_LINES:
case GE_PRIM_TRIANGLES:
case GE_PRIM_RECTANGLES:
// This is the easy one. SubmitPrimitive resets data_index_.
data_[data_index_++] = vert;
break;
case GE_PRIM_LINE_STRIP:
// This one alternates, and data_index_ > 0 means it draws a segment.
data_[(data_index_++) & 1] = vert;
break;
case GE_PRIM_TRIANGLE_STRIP:
data_[(data_index_++) % 3] = vert;
break;
case GE_PRIM_TRIANGLE_FAN:
if (data_index_ == 0) {
data_[data_index_++] = vert;
} else {
int provoking_index = 2 - ((data_index_++) % 2);
data_[provoking_index] = vert;
}
break;
default:
_assert_msg_(false, "Invalid prim type: %d", (int)prev_prim_);
break;
}
uint32_t vertTypeID = GetVertTypeID(gstate.vertType, gstate.getUVGenMode());
// This now processes the step with shared logic, given the existing data_.
isImmDraw_ = true;
SubmitPrimitive(nullptr, nullptr, GE_PRIM_KEEP_PREVIOUS, 0, vertTypeID, nullptr, drawEngine);
isImmDraw_ = false;
}
void TransformUnit::SendTriangle(CullType cullType, const VertexData *verts, int provoking) {
if (cullType == CullType::OFF) {
Clipper::ProcessTriangle(verts[0], verts[1], verts[2], verts[provoking], *binner_);

View File

@ -129,6 +129,7 @@ public:
static ScreenCoords DrawingToScreen(const DrawingCoords &coords, u16 z);
void SubmitPrimitive(const void* vertices, const void* indices, GEPrimitiveType prim_type, int vertex_count, u32 vertex_type, int *bytesRead, SoftwareDrawEngine *drawEngine);
void SubmitImmVertex(const VertexData &vert, SoftwareDrawEngine *drawEngine);
bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices);