mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-26 23:10:38 +00:00
softgpu: Support fog and color1 on imm verts.
This commit is contained in:
parent
35ba01e01f
commit
596b07bd2e
@ -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");
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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,11 +510,12 @@ 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);
|
||||
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_);
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user