Permalink
Browse files

Merge pull request #10981 from unknownbrackets/flat-shade

Use software transform for flat shading and fix colors
  • Loading branch information...
hrydgard committed Jun 6, 2018
2 parents 46683c5 + 2606365 commit 347721f200166c26cd5a11cb5cc03551037f3383
@@ -125,6 +125,33 @@ static bool IsReallyAClear(const TransformedVertex *transformed, int numVerts, f
return true;
}
static int ColorIndexOffset(int prim, GEShadeMode shadeMode, bool clearMode) {
if (shadeMode != GE_SHADE_FLAT || clearMode) {
return 0;
}
switch (prim) {
case GE_PRIM_LINES:
case GE_PRIM_LINE_STRIP:
return 1;
case GE_PRIM_TRIANGLES:
case GE_PRIM_TRIANGLE_STRIP:
return 2;
case GE_PRIM_TRIANGLE_FAN:
return 1;
case GE_PRIM_RECTANGLES:
// We already use BR color when expanding, so no need to offset.
return 0;
default:
break;
}
return 0;
}
void SoftwareTransform(
int prim, int vertexCount, u32 vertType, u16 *&inds, int indexType,
const DecVtxFormat &decVtxFormat, int &maxIndex, TransformedVertex *&drawBuffer, int &numTrans, bool &drawIndexed, const SoftwareTransformParams *params, SoftwareTransformResult *result) {
@@ -168,6 +195,11 @@ void SoftwareTransform(
fog_slope = 1.0f;
}
int colorIndOffset = 0;
if (params->provokeFlatFirst) {
colorIndOffset = ColorIndexOffset(prim, gstate.getShadeMode(), gstate.isModeClear());
}
VertexReader reader(decoded, decVtxFormat, vertType);
if (throughmode) {
for (int index = 0; index < maxIndex; index++) {
@@ -178,7 +210,13 @@ void SoftwareTransform(
reader.ReadPos(vert.pos);
if (reader.hasColor0()) {
reader.ReadColor0_8888(vert.color0);
if (colorIndOffset != 0 && index + colorIndOffset < maxIndex) {
reader.Goto(index + colorIndOffset);
reader.ReadColor0_8888(vert.color0);
reader.Goto(index);
} else {
reader.ReadColor0_8888(vert.color0);
}
} else {
vert.color0_32 = gstate.getMaterialAmbientRGBA();
}
@@ -260,7 +298,13 @@ void SoftwareTransform(
// Perform lighting here if enabled. don't need to check through, it's checked above.
Vec4f unlitColor = Vec4f(1, 1, 1, 1);
if (reader.hasColor0()) {
reader.ReadColor0(&unlitColor.x);
if (colorIndOffset != 0 && index + colorIndOffset < maxIndex) {
reader.Goto(index + colorIndOffset);
reader.ReadColor0(&unlitColor.x);
reader.Goto(index);
} else {
reader.ReadColor0(&unlitColor.x);
}
} else {
unlitColor = Vec4f::FromRGBA(gstate.getMaterialAmbientRGBA());
}
@@ -46,6 +46,7 @@ struct SoftwareTransformParams {
TextureCacheCommon *texCache;
bool allowClear;
bool allowSeparateAlphaClear;
bool provokeFlatFirst;
};
void SoftwareTransform(int prim, int vertexCount, u32 vertexType, u16 *&inds, int indexType, const DecVtxFormat &decVtxFormat, int &maxIndex, TransformedVertex *&drawBuffer,
@@ -331,7 +331,8 @@ void DrawEngineD3D11::DoFlush() {
GEPrimitiveType prim = prevPrim_;
ApplyDrawState(prim);
bool useHWTransform = CanUseHardwareTransform(prim);
// Always use software for flat shading to fix the provoking index.
bool useHWTransform = CanUseHardwareTransform(prim) && gstate.getShadeMode() != GE_SHADE_FLAT;
if (useHWTransform) {
ID3D11Buffer *vb_ = nullptr;
@@ -587,6 +588,7 @@ void DrawEngineD3D11::DoFlush() {
params.texCache = textureCache_;
params.allowClear = true;
params.allowSeparateAlphaClear = false; // D3D11 doesn't support separate alpha clears
params.provokeFlatFirst = true;
int maxIndex = indexGen.MaxIndex();
SoftwareTransform(
@@ -545,6 +545,7 @@ void DrawEngineDX9::DoFlush() {
params.texCache = textureCache_;
params.allowClear = true;
params.allowSeparateAlphaClear = true;
params.provokeFlatFirst = true;
int maxIndex = indexGen.MaxIndex();
SoftwareTransform(
@@ -135,7 +135,8 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag
if (doTexture) {
WRITE(p, " float3 v_texcoord: TEXCOORD0;\n");
}
WRITE(p, " float4 v_color0: COLOR0;\n");
const char *colorInterpolation = doFlatShading && lang == HLSL_D3D11 ? "nointerpolation " : "";
WRITE(p, " %sfloat4 v_color0: COLOR0;\n", colorInterpolation);
if (lmode) {
WRITE(p, " float3 v_color1: COLOR1;\n");
}
@@ -537,7 +537,8 @@ void ShaderManagerDX9::DirtyLastShader() { // disables vertex arrays
}
VSShader *ShaderManagerDX9::ApplyShader(int prim, u32 vertType) {
bool useHWTransform = CanUseHardwareTransform(prim);
// Always use software for flat shading to fix the provoking index.
bool useHWTransform = CanUseHardwareTransform(prim) && gstate.getShadeMode() != GE_SHADE_FLAT;
VShaderID VSID;
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
@@ -204,10 +204,13 @@ void DrawEngineDX9::ApplyDrawState(int prim) {
if (gstate.isModeClear()) {
// Set Cull
dxstate.cullMode.set(false, false);
// Well, probably doesn't matter...
dxstate.shadeMode.set(D3DSHADE_GOURAUD);
} else {
// Set cull
bool wantCull = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled();
dxstate.cullMode.set(wantCull, gstate.getCullMode());
dxstate.shadeMode.set(gstate.getShadeMode() == GE_SHADE_GOURAUD ? D3DSHADE_GOURAUD : D3DSHADE_FLAT);
}
}
@@ -231,7 +231,8 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage
if (doTexture) {
WRITE(p, " float3 v_texcoord : TEXCOORD0;\n");
}
WRITE(p, " float4 v_color0 : COLOR0;\n");
const char *colorInterpolation = doFlatShading && lang == HLSL_D3D11 ? "nointerpolation " : "";
WRITE(p, " %sfloat4 v_color0 : COLOR0;\n", colorInterpolation);
if (lmode)
WRITE(p, " float3 v_color1 : COLOR1;\n");
@@ -553,6 +553,7 @@ void DrawEngineGLES::DoFlush() {
params.texCache = textureCache_;
params.allowClear = true;
params.allowSeparateAlphaClear = true;
params.provokeFlatFirst = false;
int maxIndex = indexGen.MaxIndex();
int vertexCount = indexGen.VertexCount();
View
@@ -72,7 +72,8 @@ const CommonCommandTableEntry commonCommandTable[] = {
{ GE_CMD_FOGENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE},
{ GE_CMD_TEXMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS | DIRTY_FRAGMENTSHADER_STATE },
{ GE_CMD_TEXSHADELS, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
{ GE_CMD_SHADEMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE },
// Raster state for Direct3D 9, uncommon.
{ GE_CMD_SHADEMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_RASTER_STATE },
{ GE_CMD_TEXFUNC, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAGMENTSHADER_STATE },
{ GE_CMD_COLORTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAGMENTSHADER_STATE },
{ GE_CMD_ALPHATESTENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAGMENTSHADER_STATE },
@@ -574,7 +574,8 @@ void DrawEngineVulkan::DoFlush() {
GEPrimitiveType prim = prevPrim_;
bool useHWTransform = CanUseHardwareTransform(prim);
// Always use software for flat shading to fix the provoking index.
bool useHWTransform = CanUseHardwareTransform(prim) && gstate.getShadeMode() != GE_SHADE_FLAT;
VulkanVertexShader *vshader = nullptr;
VulkanFragmentShader *fshader = nullptr;
@@ -860,6 +861,7 @@ void DrawEngineVulkan::DoFlush() {
// do not respect scissor rects.
params.allowClear = g_Config.iRenderingMode != 0;
params.allowSeparateAlphaClear = false;
params.provokeFlatFirst = true;
int maxIndex = indexGen.MaxIndex();
SoftwareTransform(
@@ -35,6 +35,7 @@ void DirectXState::Restore() {
scissorRect.restore(); count++;
cullMode.restore(); count++;
shadeMode.restore(); count++;
depthTest.restore(); count++;
depthFunc.restore(); count++;
@@ -455,6 +455,7 @@ class DirectXState {
BoolUnused dither;
CullMode cullMode;
DxState1<D3DRS_SHADEMODE, D3DSHADE_GOURAUD> shadeMode;
BoolState<D3DRS_ZENABLE, false> depthTest;

0 comments on commit 347721f

Please sign in to comment.