Skip to content

Commit

Permalink
softgpu: Support fog and color1 on imm verts.
Browse files Browse the repository at this point in the history
  • Loading branch information
unknownbrackets committed Sep 18, 2022
1 parent 35ba01e commit 596b07b
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 43 deletions.
3 changes: 3 additions & 0 deletions GPU/Common/DrawEngineCommon.cpp
Expand Up @@ -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");
}
Expand Down
8 changes: 5 additions & 3 deletions GPU/GPUCommon.cpp
Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion GPU/Software/BinManager.cpp
Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions GPU/Software/FuncId.cpp
Expand Up @@ -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();
Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion GPU/Software/FuncId.h
Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions GPU/Software/Rasterizer.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion GPU/Software/Rasterizer.h
Expand Up @@ -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);
Expand Down
122 changes: 91 additions & 31 deletions GPU/Software/TransformUnit.cpp
Expand Up @@ -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;
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;
}
// 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);

if (color1Used != 0 && gstate.isUsingSecondaryColor()) {
WARN_LOG_REPORT_ONCE(geimmcolor1, G3D, "Imm vertex used secondary color");
for (int i = 0; i < vertexCount; i++) {
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);
}

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));
}

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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_);
Expand Down
1 change: 1 addition & 0 deletions GPU/Software/TransformUnit.h
Expand Up @@ -129,6 +129,7 @@ class TransformUnit {
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);

Expand Down

0 comments on commit 596b07b

Please sign in to comment.