Optimize away SpecularEnable and PointScaleEnable, by resetting the related variables on CPU.

This shaves off almost 50 vertex shader instructions (down to 705 with this).
This commit is contained in:
PatrickvL 2020-12-11 18:00:43 +01:00 committed by Anthony
parent bd76d67c78
commit 134dd70117
3 changed files with 87 additions and 98 deletions

View File

@ -6309,10 +6309,12 @@ void UpdateFixedFunctionShaderLight(int d3dLightIndex, Light* pShaderLight, D3DX
D3DXVec3Transform(&directionV, (D3DXVECTOR3*)&d3dLight->Direction, &viewTransform3x3);
D3DXVec3Normalize((D3DXVECTOR3*)&pShaderLight->DirectionVN, (D3DXVECTOR3*)&directionV);
bool SpecularEnable = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_SPECULARENABLE) != FALSE;
// Map D3D light to state struct
pShaderLight->Type = (float)((int)d3dLight->Type);
pShaderLight->Diffuse = toVector(d3dLight->Diffuse);
pShaderLight->Specular = toVector(d3dLight->Specular);
pShaderLight->Specular = SpecularEnable ? toVector(d3dLight->Specular) : toVector(0);
pShaderLight->Range = d3dLight->Range;
pShaderLight->Falloff = d3dLight->Falloff;
pShaderLight->Attenuation.x = d3dLight->Attenuation0;
@ -6337,7 +6339,7 @@ void UpdateFixedFunctionVertexShaderState()
{
using namespace xbox;
// Preprocessing
// Vertex blending
// Prepare vertex blending mode variables used in transforms, below
auto VertexBlend = XboxRenderStates.GetXboxRenderState(X_D3DRS_VERTEXBLEND);
// Xbox and host D3DVERTEXBLENDFLAGS :
@ -6376,14 +6378,10 @@ void UpdateFixedFunctionVertexShaderState()
// Lighting
ffShaderState.Modes.Lighting = (float)XboxRenderStates.GetXboxRenderState(X_D3DRS_LIGHTING);
ffShaderState.Modes.TwoSidedLighting = (float)XboxRenderStates.GetXboxRenderState(X_D3DRS_TWOSIDEDLIGHTING);
ffShaderState.Modes.SpecularEnable = (float)XboxRenderStates.GetXboxRenderState(X_D3DRS_SPECULARENABLE);
ffShaderState.Modes.LocalViewer = (float)XboxRenderStates.GetXboxRenderState(X_D3DRS_LOCALVIEWER);
bool ColorVertex = XboxRenderStates.GetXboxRenderState(X_D3DRS_COLORVERTEX) != FALSE;
D3DXVECTOR4 Ambient = toVector(XboxRenderStates.GetXboxRenderState(X_D3DRS_AMBIENT));
D3DXVECTOR4 BackAmbient = toVector(XboxRenderStates.GetXboxRenderState(X_D3DRS_BACKAMBIENT));
// Material sources
bool ColorVertex = XboxRenderStates.GetXboxRenderState(X_D3DRS_COLORVERTEX) != FALSE;
ffShaderState.Modes.AmbientMaterialSource = (float)(ColorVertex ? XboxRenderStates.GetXboxRenderState(X_D3DRS_AMBIENTMATERIALSOURCE) : D3DMCS_MATERIAL);
ffShaderState.Modes.DiffuseMaterialSource = (float)(ColorVertex ? XboxRenderStates.GetXboxRenderState(X_D3DRS_DIFFUSEMATERIALSOURCE) : D3DMCS_MATERIAL);
ffShaderState.Modes.SpecularMaterialSource = (float)(ColorVertex ? XboxRenderStates.GetXboxRenderState(X_D3DRS_SPECULARMATERIALSOURCE) : D3DMCS_MATERIAL);
@ -6396,14 +6394,14 @@ void UpdateFixedFunctionVertexShaderState()
// Point sprites
auto pointSize = XboxRenderStates.GetXboxRenderState(X_D3DRS_POINTSIZE);
ffShaderState.PointSprite.PointSize = *reinterpret_cast<float*>(&pointSize);
ffShaderState.PointSprite.PointScaleEnable = (float)XboxRenderStates.GetXboxRenderState(X_D3DRS_POINTSCALEENABLE);
ffShaderState.PointSprite.RenderTargetHeight = (float)GetPixelContainerHeight(g_pXbox_RenderTarget);
bool PointScaleEnable = XboxRenderStates.GetXboxRenderState(X_D3DRS_POINTSCALEENABLE) != FALSE;
ffShaderState.PointSprite.RenderTargetHeight = PointScaleEnable ? (float)GetPixelContainerHeight(g_pXbox_RenderTarget) : 1.0f;
auto scaleA = XboxRenderStates.GetXboxRenderState(X_D3DRS_POINTSCALE_A);
ffShaderState.PointSprite.ScaleA = *reinterpret_cast<float*>(&scaleA);
ffShaderState.PointSprite.ScaleA = PointScaleEnable ? *reinterpret_cast<float*>(&scaleA) : 1.0f;
auto scaleB = XboxRenderStates.GetXboxRenderState(X_D3DRS_POINTSCALE_B);
ffShaderState.PointSprite.ScaleB = *reinterpret_cast<float*>(&scaleB);
ffShaderState.PointSprite.ScaleB = PointScaleEnable ? *reinterpret_cast<float*>(&scaleB) : 0.0f;
auto scaleC = XboxRenderStates.GetXboxRenderState(X_D3DRS_POINTSCALE_C);
ffShaderState.PointSprite.ScaleC = *reinterpret_cast<float*>(&scaleC);
ffShaderState.PointSprite.ScaleC = PointScaleEnable ? *reinterpret_cast<float*>(&scaleC) : 0.0f;
// Fog
// Determine how fog depth is calculated
@ -6452,9 +6450,6 @@ void UpdateFixedFunctionVertexShaderState()
ffShaderState.TexCoordComponentCount[i] = (float)GetXboxVertexDataComponentCount(vertexDataFormat);
}
// Misc flags
ffShaderState.Modes.NormalizeNormals = (float)XboxRenderStates.GetXboxRenderState(X_D3DRS_NORMALIZENORMALS);
// Update lights
auto LightAmbient = D3DXVECTOR4(0.f, 0.f, 0.f, 0.f);
D3DXMATRIX rowMajorViewTransform;
@ -6463,8 +6458,14 @@ void UpdateFixedFunctionVertexShaderState()
UpdateFixedFunctionShaderLight(d3d8LightState.EnabledLights[i], &ffShaderState.Lights[i], &LightAmbient, rowMajorViewTransform);
}
ffShaderState.AmbientPlusLightAmbient = Ambient + LightAmbient;
ffShaderState.BackAmbientPlusLightAmbient = BackAmbient + LightAmbient;
D3DXVECTOR4 Ambient = toVector(XboxRenderStates.GetXboxRenderState(X_D3DRS_AMBIENT));
D3DXVECTOR4 BackAmbient = toVector(XboxRenderStates.GetXboxRenderState(X_D3DRS_BACKAMBIENT));
ffShaderState.TotalLightsAmbient.Front = (D3DXVECTOR3)(LightAmbient + Ambient);
ffShaderState.TotalLightsAmbient.Back = (D3DXVECTOR3)(LightAmbient + BackAmbient);
// Misc flags
ffShaderState.Modes.NormalizeNormals = (float)XboxRenderStates.GetXboxRenderState(X_D3DRS_NORMALIZENORMALS);
// Write fixed function state to shader constants
const int slotSize = 16;
@ -7344,8 +7345,6 @@ void CxbxUpdateHostTextures()
void CxbxUpdateHostTextureScaling()
{
extern xbox::X_VERTEXATTRIBUTEFORMAT* GetXboxVertexAttributeFormat(); // TMP glue
// Xbox works with "Linear" and "Swizzled" texture formats
// Linear formats are not addressed with normalized coordinates (similar to https://www.khronos.org/opengl/wiki/Rectangle_Texture?)
// We want to use normalized coordinates in our shaders, so need to be able to scale the coordinates back

View File

@ -94,28 +94,20 @@ struct TransformInfo
static TransformInfo View; // Vertex transformed to viewspace
static TransformInfo Projection; // Vertex transformed to projection space
// Vertex lighting
// Both frontface and backface lighting can be calculated
struct LightingInfo
{
float3 Front;
float3 Back;
};
// Final lighting output
struct LightingOutput
{
LightingInfo Diffuse;
LightingInfo Specular;
TwoSidedColor Diffuse;
TwoSidedColor Specular;
};
LightingInfo DoSpecular(const float3 toLightVN, const float3 toViewerVN, const float2 powers, const float4 lightSpecular)
TwoSidedColor DoSpecular(const float3 toLightVN, const float3 toViewerVN, const float2 powers, const float4 lightSpecular)
{
LightingInfo o;
o.Front = o.Back = float3(0, 0, 0);
TwoSidedColor Specular;
Specular.Front = Specular.Back = float3(0, 0, 0);
// Specular
if (state.Modes.SpecularEnable)
// Note : if (state.Modes.SpecularEnable) no longer required because when disabled, CPU sets all lightSpecular.rgb inputs to 0
{
// Blinn-Phong
// https://learnopengl.com/Advanced-Lighting/Advanced-Lighting
@ -126,12 +118,12 @@ LightingInfo DoSpecular(const float3 toLightVN, const float3 toViewerVN, const f
const float3 backSpecular = pow(abs(NdotH), powers[1]) * lightSpecular.rgb;
if (NdotH >= 0)
o.Front = frontSpecular;
Specular.Front = frontSpecular;
else
o.Back = backSpecular;
Specular.Back = backSpecular;
}
return o;
return Specular;
}
// useful reference https://drivers.amd.com/misc/samples/dx9/FixedFuncShader.pdf
@ -317,30 +309,31 @@ Material DoMaterial(const uint index, const uint diffuseReg, const uint specular
// Get the material from material state
Material material = state.Materials[index];
// Note : If X_D3DRS_COLORVERTEX is FALSE, UpdateFixedFunctionVertexShaderState has already changed all MaterialSource's into D3DMCS_MATERIAL
// Note : if (state.Modes.ColorVertex) no longer required because when disabled, CPU sets all MaterialSource's to D3DMCS_MATERIAL
{
// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dmaterialcolorsource
static const int D3DMCS_MATERIAL = 0;
static const int D3DMCS_COLOR1 = 1;
static const int D3DMCS_COLOR2 = 2;
// https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dmaterialcolorsource
static const int D3DMCS_MATERIAL = 0;
static const int D3DMCS_COLOR1 = 1;
static const int D3DMCS_COLOR2 = 2;
// If COLORVERTEX mode, AND the desired diffuse or specular colour is defined in the vertex declaration
// Then use the vertex colour instead of the material
// If COLORVERTEX mode, AND the desired diffuse or specular colour is defined in the vertex declaration
// Then use the vertex colour instead of the material
if (!vRegisterDefaultFlags[diffuseReg]) {
const float4 diffuseVertexColour = Get(xIn, diffuseReg);
if (state.Modes.AmbientMaterialSource == D3DMCS_COLOR1) material.Ambient = diffuseVertexColour;
if (state.Modes.DiffuseMaterialSource == D3DMCS_COLOR1) material.Diffuse = diffuseVertexColour;
if (state.Modes.SpecularMaterialSource == D3DMCS_COLOR1) material.Specular = diffuseVertexColour;
if (state.Modes.EmissiveMaterialSource == D3DMCS_COLOR1) material.Emissive = diffuseVertexColour;
}
if (!vRegisterDefaultFlags[diffuseReg]) {
const float4 diffuseVertexColour = Get(xIn, diffuseReg);
if (state.Modes.AmbientMaterialSource == D3DMCS_COLOR1) material.Ambient = diffuseVertexColour;
if (state.Modes.DiffuseMaterialSource == D3DMCS_COLOR1) material.Diffuse = diffuseVertexColour;
if (state.Modes.SpecularMaterialSource == D3DMCS_COLOR1) material.Specular = diffuseVertexColour;
if (state.Modes.EmissiveMaterialSource == D3DMCS_COLOR1) material.Emissive = diffuseVertexColour;
}
if (!vRegisterDefaultFlags[specularReg]) {
const float4 specularVertexColour = Get(xIn, specularReg);
if (state.Modes.AmbientMaterialSource == D3DMCS_COLOR2) material.Ambient = specularVertexColour;
if (state.Modes.DiffuseMaterialSource == D3DMCS_COLOR2) material.Diffuse = specularVertexColour;
if (state.Modes.SpecularMaterialSource == D3DMCS_COLOR2) material.Specular = specularVertexColour;
if (state.Modes.EmissiveMaterialSource == D3DMCS_COLOR2) material.Emissive = specularVertexColour;
if (!vRegisterDefaultFlags[specularReg]) {
const float4 specularVertexColour = Get(xIn, specularReg);
if (state.Modes.AmbientMaterialSource == D3DMCS_COLOR2) material.Ambient = specularVertexColour;
if (state.Modes.DiffuseMaterialSource == D3DMCS_COLOR2) material.Diffuse = specularVertexColour;
if (state.Modes.SpecularMaterialSource == D3DMCS_COLOR2) material.Specular = specularVertexColour;
if (state.Modes.EmissiveMaterialSource == D3DMCS_COLOR2) material.Emissive = specularVertexColour;
}
}
return material;
@ -474,7 +467,7 @@ float DoPointSpriteSize()
const PointSprite ps = state.PointSprite;
float pointSize = ps.PointSize;
if (ps.PointScaleEnable)
// Note : if (ps.PointScaleEnable) not required because when disabled, CPU sets RenderTargetHeight and ScaleA to 1, and ScaleB and ScaleC to 0
{
const float eyeDistance = length(View.Position);
const float factor = ps.ScaleA + ps.ScaleB * eyeDistance + ps.ScaleC * (eyeDistance * eyeDistance);
@ -541,50 +534,39 @@ VS_OUTPUT main(const VS_INPUT xInput)
// Projection transform - final position
xOut.oPos = Projection.Position;
// Diffuse and specular for when lighting is disabled
xOut.oD0 = Get(xIn, diffuse);
xOut.oD1 = Get(xIn, specular);
xOut.oB0 = Get(xIn, backDiffuse);
xOut.oB1 = Get(xIn, backSpecular);
// Vertex lighting
if (state.Modes.Lighting || state.Modes.TwoSidedLighting)
if (state.Modes.Lighting) // TODO : Remove this check by incorporating this boolean into the variables used below (set DiffuseMaterialSource to D3DMCS_COLOR1, SpecularMaterialSource to D3DMCS_COLOR2, all other to D3DMCS_MATERIAL and their colors and TotalLightsAmbient to zero, etc)
{
// Materials
const Material material = DoMaterial(0, diffuse, specular, xIn);
const Material backMaterial = DoMaterial(1, backDiffuse, backSpecular, xIn);
const float2 powers = float2(material.Power, backMaterial.Power);
LightingOutput lighting = CalcLighting(powers);
Material material = DoMaterial(0, diffuse, specular, xIn);
Material backMaterial = DoMaterial(1, backDiffuse, backSpecular, xIn);
// Compute each lighting component
const float3 _ambient = material.Ambient.rgb * state.AmbientPlusLightAmbient.rgb;
const float3 _backAmbient = backMaterial.Ambient.rgb * state.BackAmbientPlusLightAmbient.rgb;
const float3 _diffuse = material.Diffuse.rgb * lighting.Diffuse.Front;
const float3 _backDiffuse = backMaterial.Diffuse.rgb * lighting.Diffuse.Back;
const float3 _specular = material.Specular.rgb * lighting.Specular.Front;
const float3 _backSpecular = backMaterial.Specular.rgb * lighting.Specular.Back;
const float3 _emissive = material.Emissive.rgb;
const float3 _backEmissive = backMaterial.Emissive.rgb;
const float2 powers = float2(material.Power, backMaterial.Power);
const LightingOutput lighting = CalcLighting(powers);
// Frontface
xOut.oD0 = float4(_ambient + _diffuse + _emissive, material.Diffuse.a);
xOut.oD1 = float4(_specular, 0);
// Backface
xOut.oB0 = float4(_backAmbient + _backDiffuse + _backEmissive, backMaterial.Diffuse.a);
xOut.oB1 = float4(_backSpecular, 0);
}
material.Specular.rgb *= lighting.Specular.Front;
material.Diffuse.rgb *= lighting.Diffuse.Front;
material.Ambient.rgb *= state.TotalLightsAmbient.Front;
xOut.oD0 = float4(material.Diffuse.rgb + material.Ambient.rgb + material.Emissive.rgb, material.Diffuse.a);
xOut.oD1 = float4(material.Specular.rgb, 0);
// TODO does TwoSidedLighting imply Lighting? Verify if TwoSidedLighting can be enabled independently of Lighting
// Diffuse and specular for when lighting is disabled
if (!state.Modes.Lighting)
{
xOut.oD0 = Get(xIn, diffuse);
xOut.oD1 = Get(xIn, specular);
}
if(!state.Modes.TwoSidedLighting)
{
xOut.oB0 = Get(xIn, backDiffuse);
xOut.oB1 = Get(xIn, backSpecular);
if(state.Modes.TwoSidedLighting) // TODO : Same as above, for backface lighting variables
{
// Backface
backMaterial.Specular.rgb *= lighting.Specular.Back;
backMaterial.Diffuse.rgb *= lighting.Diffuse.Back;
backMaterial.Ambient.rgb *= state.TotalLightsAmbient.Back;
xOut.oB0 = float4(backMaterial.Diffuse.rgb + backMaterial.Ambient.rgb + backMaterial.Emissive.rgb, backMaterial.Diffuse.a);
xOut.oB1 = float4(backMaterial.Specular.rgb, 0);
}
}
// Colour

View File

@ -94,9 +94,10 @@ struct Modes {
alignas(16) float Lighting;
alignas(16) float TwoSidedLighting;
alignas(16) float SpecularEnable;
// alignas(16) float SpecularEnable;
alignas(16) float LocalViewer;
/// alignas(16) float ColorVertex;
alignas(16) float VertexBlend_NrOfMatrices;
alignas(16) float VertexBlend_CalcLastWeight; // Could be a bool in higer shader models
alignas(16) float NormalizeNormals;
@ -104,7 +105,7 @@ struct Modes {
struct PointSprite {
alignas(16) float PointSize;
alignas(16) float PointScaleEnable;
// alignas(16) float PointScaleEnable;
alignas(16) float RenderTargetHeight;
alignas(16) float ScaleA;
alignas(16) float ScaleB;
@ -122,11 +123,18 @@ struct Fog {
alignas(16) float DepthMode;
};
// Vertex lighting
// Both frontface and backface lighting can be calculated
struct TwoSidedColor
{
alignas(16) float3 Front;
alignas(16) float3 Back;
};
struct FixedFunctionVertexShaderState {
alignas(16) Transforms Transforms;
alignas(16) arr(Lights, Light, 8);
alignas(16) float4 AmbientPlusLightAmbient;
alignas(16) float4 BackAmbientPlusLightAmbient;
alignas(16) TwoSidedColor TotalLightsAmbient;
alignas(16) arr(Materials, Material, 2);
alignas(16) Modes Modes;
alignas(16) Fog Fog;