mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 13:30:02 +00:00
D3D9: Generate shaders directly from shader IDs, just like we do in GL.
This commit is contained in:
parent
edafa9bc17
commit
85229efef4
@ -146,6 +146,7 @@ std::string FragmentShaderDesc(const ShaderID &id) {
|
||||
if (id.Bit(FS_BIT_ENABLE_FOG)) desc << "Fog ";
|
||||
if (id.Bit(FS_BIT_COLOR_DOUBLE)) desc << "2x ";
|
||||
if (id.Bit(FS_BIT_FLATSHADE)) desc << "Flat ";
|
||||
if (id.Bit(FS_BIT_BGRA_TEXTURE)) desc << "BGRA ";
|
||||
if (id.Bit(FS_BIT_SHADER_TEX_CLAMP)) {
|
||||
desc << "TClamp";
|
||||
if (id.Bit(FS_BIT_CLAMP_S)) desc << "S";
|
||||
@ -232,6 +233,7 @@ void ComputeFragmentShaderID(ShaderID *id_out, uint32_t vertType) {
|
||||
id.SetBit(FS_BIT_CLAMP_T, gstate.isTexCoordClampedT());
|
||||
id.SetBit(FS_BIT_TEXTURE_AT_OFFSET, textureAtOffset);
|
||||
}
|
||||
id.SetBit(FS_BIT_BGRA_TEXTURE, gstate_c.bgraTexture);
|
||||
}
|
||||
|
||||
id.SetBit(FS_BIT_LMODE, lmode);
|
||||
|
@ -72,6 +72,7 @@ enum {
|
||||
FS_BIT_BLENDFUNC_A = 38, // 4 bits
|
||||
FS_BIT_BLENDFUNC_B = 42,
|
||||
FS_BIT_FLATSHADE = 46,
|
||||
FS_BIT_BGRA_TEXTURE = 47,
|
||||
};
|
||||
|
||||
struct ShaderID {
|
||||
|
@ -2186,4 +2186,20 @@ bool DIRECTX9_GPU::GetCurrentSimpleVertices(int count, std::vector<GPUDebugVerte
|
||||
return transformDraw_.GetCurrentSimpleVertices(count, vertices, indices);
|
||||
}
|
||||
|
||||
std::vector<std::string> DIRECTX9_GPU::DebugGetShaderIDs(DebugShaderType type) {
|
||||
if (type == SHADER_TYPE_VERTEXLOADER) {
|
||||
return transformDraw_.DebugGetVertexLoaderIDs();
|
||||
} else {
|
||||
return shaderManager_->DebugGetShaderIDs(type);
|
||||
}
|
||||
}
|
||||
|
||||
std::string DIRECTX9_GPU::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
|
||||
if (type == SHADER_TYPE_VERTEXLOADER) {
|
||||
return transformDraw_.DebugGetVertexLoaderString(id, stringType);
|
||||
} else {
|
||||
return shaderManager_->DebugGetShaderString(id, type, stringType);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace DX9
|
||||
|
@ -143,6 +143,10 @@ public:
|
||||
void Execute_BoneMtxNum(u32 op, u32 diff);
|
||||
void Execute_BoneMtxData(u32 op, u32 diff);
|
||||
|
||||
// Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend.
|
||||
std::vector<std::string> DebugGetShaderIDs(DebugShaderType shader) override;
|
||||
std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override;
|
||||
|
||||
protected:
|
||||
void FastRunLoop(DisplayList &list) override;
|
||||
void ProcessEvent(GPUEvent ev) override;
|
||||
|
@ -22,8 +22,8 @@
|
||||
#include "GPU/Directx9/helper/global.h"
|
||||
#include "GPU/Directx9/PixelShaderGeneratorDX9.h"
|
||||
#include "GPU/ge_constants.h"
|
||||
#include "GPU/GPUState.h"
|
||||
#include "GPU/Common/GPUStateUtils.h"
|
||||
#include "GPU/GPUState.h"
|
||||
|
||||
#define WRITE p+=sprintf
|
||||
|
||||
@ -31,131 +31,54 @@
|
||||
|
||||
namespace DX9 {
|
||||
|
||||
// Here we must take all the bits of the gstate that determine what the fragment shader will
|
||||
// look like, and concatenate them together into an ID.
|
||||
void ComputeFragmentShaderIDDX9(ShaderID *id) {
|
||||
int id0 = 0;
|
||||
int id1 = 0;
|
||||
if (gstate.isModeClear()) {
|
||||
// We only need one clear shader, so let's ignore the rest of the bits.
|
||||
id0 = 1;
|
||||
} else {
|
||||
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !gstate.isModeThrough();
|
||||
bool enableFog = gstate.isFogEnabled() && !gstate.isModeThrough();
|
||||
bool enableAlphaTest = gstate.isAlphaTestEnabled() && !IsAlphaTestTriviallyTrue() && !g_Config.bDisableAlphaTest;
|
||||
bool enableColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue();
|
||||
bool enableColorDoubling = gstate.isColorDoublingEnabled();
|
||||
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
|
||||
bool doTextureAlpha = gstate.isTextureAlphaUsed();
|
||||
ReplaceBlendType replaceBlend = ReplaceBlendWithShader(gstate_c.allowShaderBlend);
|
||||
ReplaceAlphaType stencilToAlpha = ReplaceAlphaWithStencil(replaceBlend);
|
||||
|
||||
// All texfuncs except replace are the same for RGB as for RGBA with full alpha.
|
||||
if (gstate_c.textureFullAlpha && gstate.getTextureFunction() != GE_TEXFUNC_REPLACE)
|
||||
doTextureAlpha = false;
|
||||
|
||||
// id0 |= (gstate.isModeClear() & 1);
|
||||
if (gstate.isTextureMapEnabled()) {
|
||||
id0 |= 1 << 1;
|
||||
id0 |= gstate.getTextureFunction() << 2;
|
||||
id0 |= (doTextureAlpha & 1) << 5; // rgb or rgba
|
||||
id0 |= (gstate_c.flipTexture & 1) << 6;
|
||||
|
||||
if (gstate_c.needShaderTexClamp) {
|
||||
bool textureAtOffset = gstate_c.curTextureXOffset != 0 || gstate_c.curTextureYOffset != 0;
|
||||
// 3 bits total.
|
||||
id0 |= 1 << 7;
|
||||
id0 |= gstate.isTexCoordClampedS() << 8;
|
||||
id0 |= gstate.isTexCoordClampedT() << 9;
|
||||
id0 |= (textureAtOffset & 1) << 10;
|
||||
}
|
||||
}
|
||||
|
||||
id0 |= (lmode & 1) << 11;
|
||||
#if !defined(DX9_USE_HW_ALPHA_TEST)
|
||||
if (enableAlphaTest) {
|
||||
// 5 bits total.
|
||||
id0 |= 1 << 12;
|
||||
id0 |= gstate.getAlphaTestFunction() << 13;
|
||||
id0 |= (IsAlphaTestAgainstZero() & 1) << 16;
|
||||
}
|
||||
#endif
|
||||
if (enableColorTest) {
|
||||
// 4 bits total.
|
||||
id0 |= 1 << 17;
|
||||
id0 |= gstate.getColorTestFunction() << 18;
|
||||
id0 |= (IsColorTestAgainstZero() & 1) << 20;
|
||||
}
|
||||
id0 |= (enableFog & 1) << 21;
|
||||
id0 |= (doTextureProjection & 1) << 22;
|
||||
id0 |= (enableColorDoubling & 1) << 23;
|
||||
// 2 bits
|
||||
id0 |= (stencilToAlpha) << 24;
|
||||
|
||||
if (stencilToAlpha != REPLACE_ALPHA_NO) {
|
||||
// 4 bits
|
||||
id0 |= ReplaceAlphaWithStencilType() << 26;
|
||||
}
|
||||
|
||||
if (enableAlphaTest)
|
||||
gpuStats.numAlphaTestedDraws++;
|
||||
else
|
||||
gpuStats.numNonAlphaTestedDraws++;
|
||||
|
||||
// 2 bits.
|
||||
id0 |= ReplaceLogicOpType() << 30;
|
||||
|
||||
// 3 bits.
|
||||
id1 |= replaceBlend << 0;
|
||||
if (replaceBlend > REPLACE_BLEND_STANDARD) {
|
||||
// 11 bits total.
|
||||
id1 |= gstate.getBlendEq() << 3;
|
||||
id1 |= gstate.getBlendFuncA() << 6;
|
||||
id1 |= gstate.getBlendFuncB() << 10;
|
||||
}
|
||||
|
||||
// TODO: Flat shading?
|
||||
|
||||
id1 |= (gstate_c.bgraTexture & 1) << 15;
|
||||
}
|
||||
|
||||
id->d[0] = id0;
|
||||
id->d[1] = id1;
|
||||
}
|
||||
|
||||
// Missing: Z depth range
|
||||
// Also, logic ops etc, of course. Urgh.
|
||||
void GenerateFragmentShaderDX9(char *buffer) {
|
||||
// Also, logic ops etc, of course, as they are not supported in DX9.
|
||||
bool GenerateFragmentShaderDX9(const ShaderID &id, char *buffer) {
|
||||
char *p = buffer;
|
||||
|
||||
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !gstate.isModeThrough();
|
||||
bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
|
||||
bool enableFog = gstate.isFogEnabled() && !gstate.isModeThrough() && !gstate.isModeClear();
|
||||
bool enableAlphaTest = gstate.isAlphaTestEnabled() && !IsAlphaTestTriviallyTrue() && !gstate.isModeClear() && !g_Config.bDisableAlphaTest;
|
||||
bool alphaTestAgainstZero = IsAlphaTestAgainstZero();
|
||||
bool enableColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue() && !gstate.isModeClear();
|
||||
bool colorTestAgainstZero = IsColorTestAgainstZero();
|
||||
bool enableColorDoubling = gstate.isColorDoublingEnabled() && gstate.isTextureMapEnabled();
|
||||
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
|
||||
bool doTextureAlpha = gstate.isTextureAlphaUsed();
|
||||
bool textureAtOffset = gstate_c.curTextureXOffset != 0 || gstate_c.curTextureYOffset != 0;
|
||||
ReplaceBlendType replaceBlend = ReplaceBlendWithShader(gstate_c.allowShaderBlend);
|
||||
ReplaceAlphaType stencilToAlpha = ReplaceAlphaWithStencil(replaceBlend);
|
||||
bool lmode = id.Bit(FS_BIT_LMODE);
|
||||
bool doTexture = id.Bit(FS_BIT_DO_TEXTURE);
|
||||
bool enableFog = id.Bit(FS_BIT_ENABLE_FOG);
|
||||
bool enableAlphaTest = id.Bit(FS_BIT_ALPHA_TEST);
|
||||
|
||||
if (gstate_c.textureFullAlpha && gstate.getTextureFunction() != GE_TEXFUNC_REPLACE)
|
||||
doTextureAlpha = false;
|
||||
bool alphaTestAgainstZero = id.Bit(FS_BIT_ALPHA_AGAINST_ZERO);
|
||||
bool enableColorTest = id.Bit(FS_BIT_COLOR_TEST);
|
||||
bool colorTestAgainstZero = id.Bit(FS_BIT_COLOR_AGAINST_ZERO);
|
||||
bool enableColorDoubling = id.Bit(FS_BIT_COLOR_DOUBLE);
|
||||
bool doTextureProjection = id.Bit(FS_BIT_DO_TEXTURE_PROJ);
|
||||
bool doTextureAlpha = id.Bit(FS_BIT_TEXALPHA);
|
||||
bool doFlatShading = id.Bit(FS_BIT_FLATSHADE);
|
||||
bool isModeClear = id.Bit(FS_BIT_CLEARMODE);
|
||||
|
||||
bool bgraTexture = id.Bit(FS_BIT_BGRA_TEXTURE);
|
||||
|
||||
GEComparison alphaTestFunc = (GEComparison)id.Bits(FS_BIT_ALPHA_TEST_FUNC, 3);
|
||||
GEComparison colorTestFunc = (GEComparison)id.Bits(FS_BIT_COLOR_TEST_FUNC, 2);
|
||||
bool needShaderTexClamp = id.Bit(FS_BIT_SHADER_TEX_CLAMP);
|
||||
|
||||
ReplaceBlendType replaceBlend = static_cast<ReplaceBlendType>(id.Bits(FS_BIT_REPLACE_BLEND, 3));
|
||||
ReplaceAlphaType stencilToAlpha = static_cast<ReplaceAlphaType>(id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2));
|
||||
|
||||
GETexFunc texFunc = (GETexFunc)id.Bits(FS_BIT_TEXFUNC, 3);
|
||||
bool textureAtOffset = id.Bit(FS_BIT_TEXTURE_AT_OFFSET);
|
||||
|
||||
GEBlendSrcFactor replaceBlendFuncA = (GEBlendSrcFactor)id.Bits(FS_BIT_BLENDFUNC_A, 4);
|
||||
GEBlendDstFactor replaceBlendFuncB = (GEBlendDstFactor)id.Bits(FS_BIT_BLENDFUNC_B, 4);
|
||||
GEBlendMode replaceBlendEq = (GEBlendMode)id.Bits(FS_BIT_BLENDEQ, 3);
|
||||
|
||||
StencilValueType replaceAlphaWithStencilType = (StencilValueType)id.Bits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4);
|
||||
|
||||
if (doTexture)
|
||||
WRITE(p, "sampler tex : register(s0);\n");
|
||||
if (!gstate.isModeClear() && replaceBlend > REPLACE_BLEND_STANDARD) {
|
||||
if (!isModeClear && replaceBlend > REPLACE_BLEND_STANDARD) {
|
||||
if (replaceBlend == REPLACE_BLEND_COPY_FBO) {
|
||||
WRITE(p, "float2 u_fbotexSize : register(c%i);\n", CONST_PS_FBOTEXSIZE);
|
||||
WRITE(p, "sampler fbotex : register(s1);\n");
|
||||
}
|
||||
if (gstate.getBlendFuncA() == GE_SRCBLEND_FIXA) {
|
||||
if (replaceBlendFuncA == GE_SRCBLEND_FIXA) {
|
||||
WRITE(p, "float3 u_blendFixA : register(c%i);\n", CONST_PS_BLENDFIXA);
|
||||
}
|
||||
if (gstate.getBlendFuncB() == GE_DSTBLEND_FIXB) {
|
||||
if (replaceBlendFuncB == GE_DSTBLEND_FIXB) {
|
||||
WRITE(p, "float3 u_blendFixB : register(c%i);\n", CONST_PS_BLENDFIXB);
|
||||
}
|
||||
}
|
||||
@ -170,10 +93,10 @@ void GenerateFragmentShaderDX9(char *buffer) {
|
||||
WRITE(p, "float4 u_alphacolorref : register(c%i);\n", CONST_PS_ALPHACOLORREF);
|
||||
WRITE(p, "float4 u_alphacolormask : register(c%i);\n", CONST_PS_ALPHACOLORMASK);
|
||||
}
|
||||
if (stencilToAlpha && ReplaceAlphaWithStencilType() == STENCIL_VALUE_UNIFORM) {
|
||||
if (stencilToAlpha && replaceAlphaWithStencilType == STENCIL_VALUE_UNIFORM) {
|
||||
WRITE(p, "float u_stencilReplaceValue : register(c%i);\n", CONST_PS_STENCILREPLACE);
|
||||
}
|
||||
if (gstate.isTextureMapEnabled() && gstate.getTextureFunction() == GE_TEXFUNC_BLEND) {
|
||||
if (doTexture && texFunc == GE_TEXFUNC_BLEND) {
|
||||
WRITE(p, "float3 u_texenv : register(c%i);\n", CONST_PS_TEXENV);
|
||||
}
|
||||
if (enableFog) {
|
||||
@ -205,7 +128,7 @@ void GenerateFragmentShaderDX9(char *buffer) {
|
||||
WRITE(p, "float4 main( PS_IN In ) : COLOR\n");
|
||||
WRITE(p, "{\n");
|
||||
|
||||
if (gstate.isModeClear()) {
|
||||
if (isModeClear) {
|
||||
// Clear mode does not allow any fancy shading.
|
||||
WRITE(p, " float4 v = In.v_color0;\n");
|
||||
} else {
|
||||
@ -218,10 +141,10 @@ void GenerateFragmentShaderDX9(char *buffer) {
|
||||
secondary = "";
|
||||
}
|
||||
|
||||
if (gstate.isTextureMapEnabled()) {
|
||||
if (doTexture) {
|
||||
const char *texcoord = "In.v_texcoord";
|
||||
// TODO: Not sure the right way to do this for projection.
|
||||
if (gstate_c.needShaderTexClamp) {
|
||||
if (needShaderTexClamp) {
|
||||
// We may be clamping inside a larger surface (tex = 64x64, buffer=480x272).
|
||||
// We may also be wrapping in such a surface, or either one in a too-small surface.
|
||||
// Obviously, clamping to a smaller surface won't work. But better to clamp to something.
|
||||
@ -235,12 +158,12 @@ void GenerateFragmentShaderDX9(char *buffer) {
|
||||
vcoord = "1.0 - " + vcoord;
|
||||
}
|
||||
|
||||
if (gstate.isTexCoordClampedS()) {
|
||||
if (id.Bit(FS_BIT_CLAMP_S)) {
|
||||
ucoord = "clamp(" + ucoord + ", u_texclamp.z, u_texclamp.x - u_texclamp.z)";
|
||||
} else {
|
||||
ucoord = "fmod(" + ucoord + ", u_texclamp.x)";
|
||||
}
|
||||
if (gstate.isTexCoordClampedT()) {
|
||||
if (id.Bit(FS_BIT_CLAMP_T)) {
|
||||
vcoord = "clamp(" + vcoord + ", u_texclamp.w, u_texclamp.y - u_texclamp.w)";
|
||||
} else {
|
||||
vcoord = "fmod(" + vcoord + ", u_texclamp.y)";
|
||||
@ -266,14 +189,14 @@ void GenerateFragmentShaderDX9(char *buffer) {
|
||||
}
|
||||
|
||||
if (doTextureProjection) {
|
||||
WRITE(p, " float4 t = tex2Dproj(tex, float4(In.v_texcoord.x, In.v_texcoord.y, 0, In.v_texcoord.z))%s;\n", gstate_c.bgraTexture ? ".bgra" : "");
|
||||
WRITE(p, " float4 t = tex2Dproj(tex, float4(In.v_texcoord.x, In.v_texcoord.y, 0, In.v_texcoord.z))%s;\n", bgraTexture ? ".bgra" : "");
|
||||
} else {
|
||||
WRITE(p, " float4 t = tex2D(tex, %s.xy)%s;\n", texcoord, gstate_c.bgraTexture ? ".bgra" : "");
|
||||
WRITE(p, " float4 t = tex2D(tex, %s.xy)%s;\n", texcoord, bgraTexture ? ".bgra" : "");
|
||||
}
|
||||
WRITE(p, " float4 p = In.v_color0;\n");
|
||||
|
||||
if (doTextureAlpha) { // texfmt == RGBA
|
||||
switch (gstate.getTextureFunction()) {
|
||||
switch (texFunc) {
|
||||
case GE_TEXFUNC_MODULATE:
|
||||
WRITE(p, " float4 v = p * t%s;\n", secondary); break;
|
||||
case GE_TEXFUNC_DECAL:
|
||||
@ -292,7 +215,7 @@ void GenerateFragmentShaderDX9(char *buffer) {
|
||||
}
|
||||
|
||||
} else { // texfmt == RGB
|
||||
switch (gstate.getTextureFunction()) {
|
||||
switch (texFunc) {
|
||||
case GE_TEXFUNC_MODULATE:
|
||||
WRITE(p, " float4 v = float4(t.rgb * p.rgb, p.a)%s;\n", secondary); break;
|
||||
case GE_TEXFUNC_DECAL:
|
||||
@ -318,7 +241,6 @@ void GenerateFragmentShaderDX9(char *buffer) {
|
||||
#if !defined(DX9_USE_HW_ALPHA_TEST)
|
||||
if (enableAlphaTest) {
|
||||
if (alphaTestAgainstZero) {
|
||||
GEComparison alphaTestFunc = gstate.getAlphaTestFunction();
|
||||
// When testing against 0 (extremely common), we can avoid some math.
|
||||
// 0.002 is approximately half of 1.0 / 255.0.
|
||||
if (alphaTestFunc == GE_COMP_NOTEQUAL || alphaTestFunc == GE_COMP_GREATER) {
|
||||
@ -332,7 +254,6 @@ void GenerateFragmentShaderDX9(char *buffer) {
|
||||
WRITE(p, " clip(-1);\n");
|
||||
}
|
||||
} else {
|
||||
GEComparison alphaTestFunc = gstate.getAlphaTestFunction();
|
||||
const char *alphaTestFuncs[] = { "#", "#", " != ", " == ", " >= ", " > ", " <= ", " < " }; // never/always don't make sense
|
||||
if (alphaTestFuncs[alphaTestFunc][0] != '#') {
|
||||
// TODO: Rewrite this to use clip() appropriately (like, clip(v.a - u_alphacolorref.a))
|
||||
@ -346,7 +267,6 @@ void GenerateFragmentShaderDX9(char *buffer) {
|
||||
#endif
|
||||
if (enableColorTest) {
|
||||
if (colorTestAgainstZero) {
|
||||
GEComparison colorTestFunc = gstate.getColorTestFunction();
|
||||
// When testing against 0 (common), we can avoid some math.
|
||||
// 0.002 is approximately half of 1.0 / 255.0.
|
||||
if (colorTestFunc == GE_COMP_NOTEQUAL) {
|
||||
@ -360,9 +280,7 @@ void GenerateFragmentShaderDX9(char *buffer) {
|
||||
WRITE(p, " clip(-1);\n");
|
||||
}
|
||||
} else {
|
||||
GEComparison colorTestFunc = gstate.getColorTestFunction();
|
||||
const char *colorTestFuncs[] = { "#", "#", " != ", " == " }; // never/always don't make sense
|
||||
u32 colorTestMask = gstate.getColorTestMask();
|
||||
if (colorTestFuncs[colorTestFunc][0] != '#') {
|
||||
const char * test = colorTestFuncs[colorTestFunc];
|
||||
WRITE(p, " float3 colortest = roundAndScaleTo255v(v.rgb);\n");
|
||||
@ -386,9 +304,8 @@ void GenerateFragmentShaderDX9(char *buffer) {
|
||||
}
|
||||
|
||||
if (replaceBlend == REPLACE_BLEND_PRE_SRC || replaceBlend == REPLACE_BLEND_PRE_SRC_2X_ALPHA) {
|
||||
GEBlendSrcFactor funcA = gstate.getBlendFuncA();
|
||||
const char *srcFactor = "ERROR";
|
||||
switch (funcA) {
|
||||
switch (replaceBlendFuncA) {
|
||||
case GE_SRCBLEND_DSTCOLOR: srcFactor = "ERROR"; break;
|
||||
case GE_SRCBLEND_INVDSTCOLOR: srcFactor = "ERROR"; break;
|
||||
case GE_SRCBLEND_SRCALPHA: srcFactor = "float3(v.a, v.a, v.a)"; break;
|
||||
@ -417,7 +334,7 @@ void GenerateFragmentShaderDX9(char *buffer) {
|
||||
std::string replacedAlpha = "0.0";
|
||||
char replacedAlphaTemp[64] = "";
|
||||
if (stencilToAlpha != REPLACE_ALPHA_NO) {
|
||||
switch (ReplaceAlphaWithStencilType()) {
|
||||
switch (replaceAlphaWithStencilType) {
|
||||
case STENCIL_VALUE_UNIFORM:
|
||||
replacedAlpha = "u_stencilReplaceValue";
|
||||
break;
|
||||
@ -467,7 +384,8 @@ void GenerateFragmentShaderDX9(char *buffer) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (ReplaceLogicOpType()) {
|
||||
LogicOpReplaceType replaceLogicOpType = (LogicOpReplaceType)id.Bits(FS_BIT_REPLACE_LOGIC_OP_TYPE, 2);
|
||||
switch (replaceLogicOpType) {
|
||||
case LOGICOPTYPE_ONE:
|
||||
WRITE(p, " v.rgb = float3(1.0, 1.0, 1.0);\n");
|
||||
break;
|
||||
@ -480,6 +398,7 @@ void GenerateFragmentShaderDX9(char *buffer) {
|
||||
|
||||
WRITE(p, " return v;\n");
|
||||
WRITE(p, "}\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -26,8 +26,7 @@
|
||||
|
||||
namespace DX9 {
|
||||
|
||||
void ComputeFragmentShaderIDDX9(ShaderID *id);
|
||||
void GenerateFragmentShaderDX9(char *buffer);
|
||||
bool GenerateFragmentShaderDX9(const ShaderID &id, char *buffer);
|
||||
|
||||
#define CONST_PS_TEXENV 0
|
||||
#define CONST_PS_ALPHACOLORREF 1
|
||||
|
@ -39,7 +39,7 @@
|
||||
|
||||
namespace DX9 {
|
||||
|
||||
PSShader::PSShader(const char *code, bool useHWTransform) : shader(nullptr), failed_(false), useHWTransform_(useHWTransform) {
|
||||
PSShader::PSShader(ShaderID id, const char *code, bool useHWTransform) : id_(id), shader(nullptr), failed_(false), useHWTransform_(useHWTransform) {
|
||||
source_ = code;
|
||||
#ifdef SHADERLOG
|
||||
OutputDebugString(ConvertUTF8ToWString(code).c_str());
|
||||
@ -79,7 +79,18 @@ PSShader::~PSShader() {
|
||||
shader->Release();
|
||||
}
|
||||
|
||||
VSShader::VSShader(const char *code, int vertType, bool useHWTransform) : shader(nullptr), failed_(false), useHWTransform_(useHWTransform) {
|
||||
std::string PSShader::GetShaderString(DebugShaderStringType type) const {
|
||||
switch (type) {
|
||||
case SHADER_STRING_SOURCE_CODE:
|
||||
return source_;
|
||||
case SHADER_STRING_SHORT_DESC:
|
||||
return FragmentShaderDesc(id_);
|
||||
default:
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
VSShader::VSShader(ShaderID id, const char *code, int vertType, bool useHWTransform) : id_(id), shader(nullptr), failed_(false), useHWTransform_(useHWTransform) {
|
||||
source_ = code;
|
||||
#ifdef SHADERLOG
|
||||
OutputDebugString(ConvertUTF8ToWString(code).c_str());
|
||||
@ -118,6 +129,16 @@ VSShader::~VSShader() {
|
||||
shader->Release();
|
||||
}
|
||||
|
||||
std::string VSShader::GetShaderString(DebugShaderStringType type) const {
|
||||
switch (type) {
|
||||
case SHADER_STRING_SOURCE_CODE:
|
||||
return source_;
|
||||
case SHADER_STRING_SHORT_DESC:
|
||||
return VertexShaderDesc(id_);
|
||||
default:
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderManagerDX9::PSSetColorUniform3(int creg, u32 color) {
|
||||
const float col[4] = {
|
||||
@ -591,12 +612,12 @@ void ShaderManagerDX9::DirtyLastShader() { // disables vertex arrays
|
||||
|
||||
|
||||
VSShader *ShaderManagerDX9::ApplyShader(int prim, u32 vertType) {
|
||||
bool useHWTransform = CanUseHardwareTransformDX9(prim);
|
||||
bool useHWTransform = CanUseHardwareTransform(prim);
|
||||
|
||||
ShaderID VSID;
|
||||
ComputeVertexShaderIDDX9(&VSID, vertType, useHWTransform);
|
||||
ComputeVertexShaderID(&VSID, vertType, useHWTransform);
|
||||
ShaderID FSID;
|
||||
ComputeFragmentShaderIDDX9(&FSID);
|
||||
ComputeFragmentShaderID(&FSID, vertType);
|
||||
|
||||
// Just update uniforms if this is the same shader as last time.
|
||||
if (lastVShader_ != nullptr && lastPShader_ != nullptr && VSID == lastVSID_ && FSID == lastFSID_) {
|
||||
@ -612,21 +633,23 @@ VSShader *ShaderManagerDX9::ApplyShader(int prim, u32 vertType) {
|
||||
VSShader *vs;
|
||||
if (vsIter == vsCache_.end()) {
|
||||
// Vertex shader not in cache. Let's compile it.
|
||||
GenerateVertexShaderDX9(prim, codeBuffer_, useHWTransform);
|
||||
vs = new VSShader(codeBuffer_, vertType, useHWTransform);
|
||||
GenerateVertexShaderDX9(VSID, codeBuffer_);
|
||||
vs = new VSShader(VSID, codeBuffer_, vertType, useHWTransform);
|
||||
|
||||
if (vs->Failed()) {
|
||||
ERROR_LOG(HLE, "Shader compilation failed, falling back to software transform");
|
||||
osm.Show("hardware transform error - falling back to software", 2.5f, 0xFF3030FF, -1, true);
|
||||
delete vs;
|
||||
|
||||
ComputeVertexShaderID(&VSID, vertType, false);
|
||||
|
||||
// TODO: Look for existing shader with the appropriate ID, use that instead of generating a new one - however, need to make sure
|
||||
// that that shader ID is not used when computing the linked shader ID below, because then IDs won't match
|
||||
// next time and we'll do this over and over...
|
||||
|
||||
// Can still work with software transform.
|
||||
GenerateVertexShaderDX9(prim, codeBuffer_, false);
|
||||
vs = new VSShader(codeBuffer_, vertType, false);
|
||||
GenerateVertexShaderDX9(VSID, codeBuffer_);
|
||||
vs = new VSShader(VSID, codeBuffer_, vertType, false);
|
||||
}
|
||||
|
||||
vsCache_[VSID] = vs;
|
||||
@ -639,8 +662,8 @@ VSShader *ShaderManagerDX9::ApplyShader(int prim, u32 vertType) {
|
||||
PSShader *fs;
|
||||
if (fsIter == fsCache_.end()) {
|
||||
// Fragment shader not in cache. Let's compile it.
|
||||
GenerateFragmentShaderDX9(codeBuffer_);
|
||||
fs = new PSShader(codeBuffer_, useHWTransform);
|
||||
GenerateFragmentShaderDX9(FSID, codeBuffer_);
|
||||
fs = new PSShader(FSID, codeBuffer_, useHWTransform);
|
||||
fsCache_[FSID] = fs;
|
||||
} else {
|
||||
fs = fsIter->second;
|
||||
@ -662,4 +685,54 @@ VSShader *ShaderManagerDX9::ApplyShader(int prim, u32 vertType) {
|
||||
return vs;
|
||||
}
|
||||
|
||||
std::vector<std::string> ShaderManagerDX9::DebugGetShaderIDs(DebugShaderType type) {
|
||||
std::string id;
|
||||
std::vector<std::string> ids;
|
||||
switch (type) {
|
||||
case SHADER_TYPE_VERTEX:
|
||||
{
|
||||
for (auto iter : vsCache_) {
|
||||
iter.first.ToString(&id);
|
||||
ids.push_back(id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SHADER_TYPE_FRAGMENT:
|
||||
{
|
||||
for (auto iter : fsCache_) {
|
||||
iter.first.ToString(&id);
|
||||
ids.push_back(id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
std::string ShaderManagerDX9::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
|
||||
ShaderID shaderId;
|
||||
shaderId.FromString(id);
|
||||
switch (type) {
|
||||
case SHADER_TYPE_VERTEX:
|
||||
{
|
||||
auto iter = vsCache_.find(shaderId);
|
||||
if (iter == vsCache_.end()) {
|
||||
return "";
|
||||
}
|
||||
return iter->second->GetShaderString(stringType);
|
||||
}
|
||||
|
||||
case SHADER_TYPE_FRAGMENT:
|
||||
{
|
||||
auto iter = fsCache_.find(shaderId);
|
||||
if (iter == fsCache_.end()) {
|
||||
return "";
|
||||
}
|
||||
return iter->second->GetShaderString(stringType);
|
||||
}
|
||||
default:
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "Globals.h"
|
||||
#include "GPU/Directx9/VertexShaderGeneratorDX9.h"
|
||||
#include "GPU/Directx9/PixelShaderGeneratorDX9.h"
|
||||
#include "GPU/Common/ShaderCommon.h"
|
||||
#include "GPU/Common/ShaderId.h"
|
||||
#include "thin3d/d3dx9_loader.h"
|
||||
#include "math/lin/matrix4x4.h"
|
||||
@ -80,38 +81,44 @@ enum {
|
||||
|
||||
class PSShader {
|
||||
public:
|
||||
PSShader(const char *code, bool useHWTransform);
|
||||
PSShader(ShaderID id, const char *code, bool useHWTransform);
|
||||
~PSShader();
|
||||
|
||||
const std::string &source() const { return source_; }
|
||||
|
||||
bool Failed() const { return failed_; }
|
||||
bool UseHWTransform() const { return useHWTransform_; }
|
||||
|
||||
|
||||
std::string GetShaderString(DebugShaderStringType type) const;
|
||||
|
||||
LPDIRECT3DPIXELSHADER9 shader;
|
||||
|
||||
protected:
|
||||
std::string source_;
|
||||
bool failed_;
|
||||
bool useHWTransform_;
|
||||
ShaderID id_;
|
||||
};
|
||||
|
||||
class VSShader {
|
||||
public:
|
||||
VSShader(const char *code, int vertType, bool useHWTransform);
|
||||
VSShader(ShaderID id, const char *code, int vertType, bool useHWTransform);
|
||||
~VSShader();
|
||||
|
||||
const std::string &source() const { return source_; }
|
||||
|
||||
bool Failed() const { return failed_; }
|
||||
bool UseHWTransform() const { return useHWTransform_; }
|
||||
|
||||
|
||||
std::string GetShaderString(DebugShaderStringType type) const;
|
||||
|
||||
LPDIRECT3DVERTEXSHADER9 shader;
|
||||
|
||||
protected:
|
||||
std::string source_;
|
||||
bool failed_;
|
||||
bool useHWTransform_;
|
||||
ShaderID id_;
|
||||
};
|
||||
|
||||
class ShaderManagerDX9 {
|
||||
@ -130,6 +137,9 @@ public:
|
||||
int NumVertexShaders() const { return (int)vsCache_.size(); }
|
||||
int NumFragmentShaders() const { return (int)fsCache_.size(); }
|
||||
|
||||
std::vector<std::string> DebugGetShaderIDs(DebugShaderType type);
|
||||
std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType);
|
||||
|
||||
private:
|
||||
void PSUpdateUniforms(int dirtyUniforms);
|
||||
void VSUpdateUniforms(int dirtyUniforms);
|
||||
|
@ -129,39 +129,60 @@ enum DoLightComputation {
|
||||
LIGHT_FULL,
|
||||
};
|
||||
|
||||
void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
void GenerateVertexShaderDX9(const ShaderID &id, char *buffer) {
|
||||
char *p = buffer;
|
||||
const u32 vertType = gstate.vertType;
|
||||
|
||||
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !gstate.isModeThrough();
|
||||
bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
|
||||
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
|
||||
bool doShadeMapping = gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP;
|
||||
bool isModeThrough = id.Bit(VS_BIT_IS_THROUGH);
|
||||
bool lmode = id.Bit(VS_BIT_LMODE) && !isModeThrough; // TODO: Different expression than in shaderIDgen
|
||||
bool doTexture = id.Bit(VS_BIT_DO_TEXTURE);
|
||||
bool doTextureProjection = id.Bit(VS_BIT_DO_TEXTURE_PROJ);
|
||||
|
||||
bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0 || !useHWTransform;
|
||||
bool hasNormal = (vertType & GE_VTYPE_NRM_MASK) != 0 && useHWTransform;
|
||||
bool hasTexcoord = (vertType & GE_VTYPE_TC_MASK) != 0 || !useHWTransform;
|
||||
bool enableFog = gstate.isFogEnabled() && !gstate.isModeThrough() && !gstate.isModeClear();
|
||||
bool throughmode = (vertType & GE_VTYPE_THROUGH_MASK) != 0;
|
||||
bool flipV = gstate_c.flipTexture;
|
||||
bool flipNormal = gstate.areNormalsReversed();
|
||||
bool prescale = g_Config.bPrescaleUV && !throughmode && (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_COORDS || gstate.getUVGenMode() == GE_TEXMAP_UNKNOWN);
|
||||
GETexMapMode uvGenMode = static_cast<GETexMapMode>(id.Bits(VS_BIT_UVGEN_MODE, 2));
|
||||
|
||||
DoLightComputation doLight[4] = {LIGHT_OFF, LIGHT_OFF, LIGHT_OFF, LIGHT_OFF};
|
||||
// this is only valid for some settings of uvGenMode
|
||||
GETexProjMapMode uvProjMode = static_cast<GETexProjMapMode>(id.Bits(VS_BIT_UVPROJ_MODE, 2));
|
||||
bool doShadeMapping = uvGenMode == GE_TEXMAP_ENVIRONMENT_MAP;
|
||||
bool doFlatShading = id.Bit(VS_BIT_FLATSHADE);
|
||||
|
||||
bool useHWTransform = id.Bit(VS_BIT_USE_HW_TRANSFORM);
|
||||
bool hasColor = id.Bit(VS_BIT_HAS_COLOR) || !useHWTransform;
|
||||
bool hasNormal = id.Bit(VS_BIT_HAS_NORMAL) && useHWTransform;
|
||||
bool hasTexcoord = id.Bit(VS_BIT_HAS_TEXCOORD) || !useHWTransform;
|
||||
bool enableFog = id.Bit(VS_BIT_ENABLE_FOG);
|
||||
bool throughmode = id.Bit(VS_BIT_IS_THROUGH);
|
||||
bool flipV = id.Bit(VS_BIT_FLIP_TEXTURE); // This also means that we are texturing from a render target
|
||||
bool flipNormal = id.Bit(VS_BIT_NORM_REVERSE);
|
||||
int ls0 = id.Bits(VS_BIT_LS0, 2);
|
||||
int ls1 = id.Bits(VS_BIT_LS1, 2);
|
||||
bool enableBones = id.Bit(VS_BIT_ENABLE_BONES);
|
||||
bool enableLighting = id.Bit(VS_BIT_LIGHTING_ENABLE);
|
||||
int matUpdate = id.Bits(VS_BIT_MATERIAL_UPDATE, 3);
|
||||
|
||||
bool prescale = g_Config.bPrescaleUV && !throughmode && (uvGenMode == GE_TEXMAP_TEXTURE_COORDS || uvGenMode == GE_TEXMAP_UNKNOWN);
|
||||
|
||||
DoLightComputation doLight[4] = { LIGHT_OFF, LIGHT_OFF, LIGHT_OFF, LIGHT_OFF };
|
||||
if (useHWTransform) {
|
||||
int shadeLight0 = doShadeMapping ? gstate.getUVLS0() : -1;
|
||||
int shadeLight1 = doShadeMapping ? gstate.getUVLS1() : -1;
|
||||
int shadeLight0 = doShadeMapping ? ls0 : -1;
|
||||
int shadeLight1 = doShadeMapping ? ls1 : -1;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (i == shadeLight0 || i == shadeLight1)
|
||||
doLight[i] = LIGHT_SHADE;
|
||||
if (gstate.isLightingEnabled() && gstate.isLightChanEnabled(i))
|
||||
if (id.Bit(VS_BIT_LIGHTING_ENABLE) && id.Bit(VS_BIT_LIGHT0_ENABLE + i))
|
||||
doLight[i] = LIGHT_FULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int numBoneWeights = 0;
|
||||
int boneWeightScale = id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2);
|
||||
if (enableBones) {
|
||||
numBoneWeights = 1 + id.Bits(VS_BIT_BONES, 3);
|
||||
}
|
||||
int texFmtScale = id.Bits(VS_BIT_TEXCOORD_FMTSCALE, 2);
|
||||
|
||||
WRITE(p, "#pragma warning( disable : 3571 )\n");
|
||||
|
||||
if (gstate.isModeThrough()) {
|
||||
if (isModeThrough) {
|
||||
WRITE(p, "float4x4 u_proj_through : register(c%i);\n", CONST_VS_PROJ_THROUGH);
|
||||
} else {
|
||||
WRITE(p, "float4x4 u_proj : register(c%i);\n", CONST_VS_PROJ);
|
||||
@ -180,17 +201,16 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
WRITE(p, "float4x3 u_view : register(c%i);\n", CONST_VS_VIEW);
|
||||
if (doTextureProjection)
|
||||
WRITE(p, "float4x3 u_texmtx : register(c%i);\n", CONST_VS_TEXMTX);
|
||||
if (vertTypeIsSkinningEnabled(vertType)) {
|
||||
int numBones = TranslateNumBones(vertTypeGetNumBoneWeights(vertType));
|
||||
if (enableBones) {
|
||||
#ifdef USE_BONE_ARRAY
|
||||
WRITE(p, "float4x3 u_bone[%i] : register(c%i);\n", numBones, CONST_VS_BONE0);
|
||||
#else
|
||||
for (int i = 0; i < numBones; i++) {
|
||||
for (int i = 0; i < numBoneWeights; i++) {
|
||||
WRITE(p, "float4x3 u_bone%i : register(c%i);\n", i, CONST_VS_BONE0 + i * 3);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (doTexture && (flipV || !prescale || gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP || gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX)) {
|
||||
if (doTexture && (flipV || !prescale || uvGenMode == GE_TEXMAP_ENVIRONMENT_MAP || uvGenMode == GE_TEXMAP_TEXTURE_MATRIX)) {
|
||||
WRITE(p, "float4 u_uvscaleoffset : register(c%i);\n", CONST_VS_UVSCALEOFFSET);
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
@ -199,7 +219,8 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
WRITE(p, "float3 u_lightpos%i : register(c%i);\n", i, CONST_VS_LIGHTPOS + i);
|
||||
}
|
||||
if (doLight[i] == LIGHT_FULL) {
|
||||
GELightType type = gstate.getLightType(i);
|
||||
GELightType type = static_cast<GELightType>(id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2));
|
||||
GELightComputation comp = static_cast<GELightComputation>(id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2));
|
||||
|
||||
if (type != GE_LIGHTTYPE_DIRECTIONAL)
|
||||
WRITE(p, "float3 u_lightatt%i : register(c%i);\n", i, CONST_VS_LIGHTATT + i);
|
||||
@ -212,11 +233,12 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
WRITE(p, "float3 u_lightambient%i : register(c%i);\n", i, CONST_VS_LIGHTAMBIENT + i);
|
||||
WRITE(p, "float3 u_lightdiffuse%i : register(c%i);\n", i, CONST_VS_LIGHTDIFFUSE + i);
|
||||
|
||||
if (gstate.isUsingSpecularLight(i))
|
||||
if (comp != GE_LIGHTCOMP_ONLYDIFFUSE) {
|
||||
WRITE(p, "float3 u_lightspecular%i : register(c%i);\n", i, CONST_VS_LIGHTSPECULAR + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gstate.isLightingEnabled()) {
|
||||
if (enableLighting) {
|
||||
WRITE(p, "float4 u_ambient : register(c%i);\n", CONST_VS_AMBIENT);
|
||||
if ((gstate.materialupdate & 2) == 0 || !hasColor)
|
||||
WRITE(p, "float3 u_matdiffuse : register(c%i);\n", CONST_VS_MATDIFFUSE);
|
||||
@ -226,15 +248,15 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!gstate.isModeThrough() && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||
if (!isModeThrough && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||
WRITE(p, "float4 u_depthRange : register(c%i);\n", CONST_VS_DEPTHRANGE);
|
||||
}
|
||||
|
||||
// And the "varyings".
|
||||
if (useHWTransform) {
|
||||
WRITE(p, "struct VS_IN { \n");
|
||||
if (vertTypeIsSkinningEnabled(vertType)) {
|
||||
WRITE(p, "%s", boneWeightAttrDecl[TranslateNumBones(vertTypeGetNumBoneWeights(vertType))]);
|
||||
if (enableBones) {
|
||||
WRITE(p, "%s", boneWeightAttrDecl[numBoneWeights]);
|
||||
}
|
||||
if (doTexture && hasTexcoord) {
|
||||
WRITE(p, " float2 texcoord : TEXCOORD0;\n");
|
||||
@ -286,7 +308,7 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
|
||||
// Confirmed: Through mode gets through exactly the same in GL and D3D in Phantasy Star: Text is 38023.0 in the test scene.
|
||||
|
||||
if (!gstate.isModeThrough() && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||
if (!isModeThrough && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||
// Apply the projection and viewport to get the Z buffer value, floor to integer, undo the viewport and projection.
|
||||
// The Z range in D3D is different but we compensate for that using parameters.
|
||||
WRITE(p, "\nfloat4 depthRoundZVP(float4 v) {\n");
|
||||
@ -336,7 +358,7 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
}
|
||||
} else {
|
||||
// Step 1: World Transform / Skinning
|
||||
if (!vertTypeIsSkinningEnabled(vertType)) {
|
||||
if (!enableBones) {
|
||||
// No skinning, just standard T&L.
|
||||
WRITE(p, " float3 worldpos = mul(float4(In.position.xyz, 1.0), u_world);\n");
|
||||
if (hasNormal)
|
||||
@ -344,8 +366,6 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
else
|
||||
WRITE(p, " float3 worldnormal = float3(0.0, 0.0, 1.0);\n");
|
||||
} else {
|
||||
int numWeights = TranslateNumBones(vertTypeGetNumBoneWeights(vertType));
|
||||
|
||||
static const char * const boneWeightAttr[8] = {
|
||||
"a_w1.x", "a_w1.y", "a_w1.z", "a_w1.w",
|
||||
"a_w2.x", "a_w2.y", "a_w2.z", "a_w2.w",
|
||||
@ -355,7 +375,7 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
|
||||
// To loop through the weights, we unfortunately need to put them in a float array.
|
||||
// GLSL ES sucks - no way to directly initialize an array!
|
||||
switch (numWeights) {
|
||||
switch (numBoneWeights) {
|
||||
case 1: WRITE(p, " float w[1]; w[0] = a_w1;\n"); break;
|
||||
case 2: WRITE(p, " float w[2]; w[0] = a_w1.x; w[1] = a_w1.y;\n"); break;
|
||||
case 3: WRITE(p, " float w[3]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z;\n"); break;
|
||||
@ -367,8 +387,8 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
}
|
||||
|
||||
WRITE(p, " mat4 skinMatrix = w[0] * u_bone[0];\n");
|
||||
if (numWeights > 1) {
|
||||
WRITE(p, " for (int i = 1; i < %i; i++) {\n", numWeights);
|
||||
if (numBoneWeights > 1) {
|
||||
WRITE(p, " for (int i = 1; i < %i; i++) {\n", numBoneWeights);
|
||||
WRITE(p, " skinMatrix += w[i] * u_bone[i];\n");
|
||||
WRITE(p, " }\n");
|
||||
}
|
||||
@ -376,29 +396,29 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
#else
|
||||
|
||||
#ifdef USE_BONE_ARRAY
|
||||
if (numWeights == 1)
|
||||
if (numBoneWeights == 1)
|
||||
WRITE(p, " float4x3 skinMatrix = a_w1 * u_bone[0]");
|
||||
else
|
||||
WRITE(p, " float4x3 skinMatrix = a_w1.x * u_bone[0]");
|
||||
for (int i = 1; i < numWeights; i++) {
|
||||
for (int i = 1; i < numBoneWeights; i++) {
|
||||
const char *weightAttr = boneWeightAttr[i];
|
||||
// workaround for "cant do .x of scalar" issue
|
||||
if (numWeights == 1 && i == 0) weightAttr = "a_w1";
|
||||
if (numWeights == 5 && i == 4) weightAttr = "a_w2";
|
||||
if (numBoneWeights == 1 && i == 0) weightAttr = "a_w1";
|
||||
if (numBoneWeights == 5 && i == 4) weightAttr = "a_w2";
|
||||
WRITE(p, " + %s * u_bone[%i]", weightAttr, i);
|
||||
}
|
||||
#else
|
||||
// Uncomment this to screw up bone shaders to check the vertex shader software fallback
|
||||
// WRITE(p, "THIS SHOULD ERROR! #error");
|
||||
if (numWeights == 1)
|
||||
if (numBoneWeights == 1)
|
||||
WRITE(p, " float4x3 skinMatrix = mul(In.a_w1, u_bone0)");
|
||||
else
|
||||
WRITE(p, " float4x3 skinMatrix = mul(In.a_w1.x, u_bone0)");
|
||||
for (int i = 1; i < numWeights; i++) {
|
||||
for (int i = 1; i < numBoneWeights; i++) {
|
||||
const char *weightAttr = boneWeightAttr[i];
|
||||
// workaround for "cant do .x of scalar" issue
|
||||
if (numWeights == 1 && i == 0) weightAttr = "a_w1";
|
||||
if (numWeights == 5 && i == 4) weightAttr = "a_w2";
|
||||
if (numBoneWeights == 1 && i == 0) weightAttr = "a_w1";
|
||||
if (numBoneWeights == 5 && i == 4) weightAttr = "a_w2";
|
||||
WRITE(p, " + mul(In.%s, u_bone%i)", weightAttr, i);
|
||||
}
|
||||
#endif
|
||||
@ -437,16 +457,17 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
bool specularIsZero = true;
|
||||
bool distanceNeeded = false;
|
||||
|
||||
if (gstate.isLightingEnabled()) {
|
||||
if (enableLighting) {
|
||||
WRITE(p, " float4 lightSum0 = u_ambient * %s + float4(u_matemissive, 0.0);\n", ambientStr);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
GELightType type = static_cast<GELightType>(id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2));
|
||||
GELightComputation comp = static_cast<GELightComputation>(id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2));
|
||||
if (doLight[i] != LIGHT_FULL)
|
||||
continue;
|
||||
diffuseIsZero = false;
|
||||
if (gstate.isUsingSpecularLight(i))
|
||||
if (comp != GE_LIGHTCOMP_ONLYDIFFUSE)
|
||||
specularIsZero = false;
|
||||
GELightType type = gstate.getLightType(i);
|
||||
if (type != GE_LIGHTTYPE_DIRECTIONAL)
|
||||
distanceNeeded = true;
|
||||
}
|
||||
@ -470,7 +491,8 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
if (doLight[i] != LIGHT_FULL)
|
||||
continue;
|
||||
|
||||
GELightType type = gstate.getLightType(i);
|
||||
GELightType type = static_cast<GELightType>(id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2));
|
||||
GELightComputation comp = static_cast<GELightComputation>(id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2));
|
||||
|
||||
if (type == GE_LIGHTTYPE_DIRECTIONAL) {
|
||||
// We prenormalize light positions for directional lights.
|
||||
@ -481,8 +503,8 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
WRITE(p, " toLight /= distance;\n");
|
||||
}
|
||||
|
||||
bool doSpecular = gstate.isUsingSpecularLight(i);
|
||||
bool poweredDiffuse = gstate.isUsingPoweredDiffuseLight(i);
|
||||
bool doSpecular = comp != GE_LIGHTCOMP_ONLYDIFFUSE;
|
||||
bool poweredDiffuse = comp == GE_LIGHTCOMP_BOTHWITHPOWDIFFUSE;
|
||||
|
||||
if (poweredDiffuse) {
|
||||
WRITE(p, " float dot%i = pow(dot(toLight, worldnormal), u_matspecular.a);\n", i);
|
||||
@ -525,7 +547,7 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
WRITE(p, " lightSum0.rgb += (u_lightambient%i * %s.rgb + diffuse)%s;\n", i, ambientStr, timesLightScale);
|
||||
}
|
||||
|
||||
if (gstate.isLightingEnabled()) {
|
||||
if (enableLighting) {
|
||||
// Sum up ambient, emissive here.
|
||||
if (lmode) {
|
||||
WRITE(p, " Out.v_color0 = clamp(lightSum0, 0.0, 1.0);\n");
|
||||
@ -555,7 +577,7 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
|
||||
// Step 3: UV generation
|
||||
if (doTexture) {
|
||||
switch (gstate.getUVGenMode()) {
|
||||
switch (uvGenMode) {
|
||||
case GE_TEXMAP_TEXTURE_COORDS: // Scale-offset. Easy.
|
||||
case GE_TEXMAP_UNKNOWN: // Not sure what this is, but Riviera uses it. Treating as coords works.
|
||||
if (prescale && !flipV) {
|
||||
@ -576,7 +598,7 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
case GE_TEXMAP_TEXTURE_MATRIX: // Projection mapping.
|
||||
{
|
||||
std::string temp_tc;
|
||||
switch (gstate.getUVProjMode()) {
|
||||
switch (uvProjMode) {
|
||||
case GE_PROJMAP_POSITION: // Use model space XYZ as source
|
||||
temp_tc = "float4(In.position.xyz, 1.0)";
|
||||
break;
|
||||
@ -617,7 +639,7 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
}
|
||||
|
||||
// Will flip in the fragment for GE_TEXMAP_TEXTURE_MATRIX.
|
||||
if (flipV && gstate.getUVGenMode() != GE_TEXMAP_TEXTURE_MATRIX)
|
||||
if (flipV && uvGenMode != GE_TEXMAP_TEXTURE_MATRIX)
|
||||
WRITE(p, " Out.v_texcoord.y = 1.0 - Out.v_texcoord.y;\n");
|
||||
}
|
||||
|
||||
|
@ -25,40 +25,7 @@ namespace DX9 {
|
||||
|
||||
// #define USE_BONE_ARRAY
|
||||
|
||||
struct VertexShaderIDDX9
|
||||
{
|
||||
VertexShaderIDDX9() {d[0] = 0xFFFFFFFF;}
|
||||
void clear() {d[0] = 0xFFFFFFFF;}
|
||||
u32 d[2];
|
||||
bool operator < (const VertexShaderIDDX9 &other) const
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(d) / sizeof(u32); i++)
|
||||
{
|
||||
if (d[i] < other.d[i])
|
||||
return true;
|
||||
if (d[i] > other.d[i])
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool operator == (const VertexShaderIDDX9 &other) const
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(d) / sizeof(u32); i++)
|
||||
{
|
||||
if (d[i] != other.d[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
bool CanUseHardwareTransformDX9(int prim);
|
||||
|
||||
void ComputeVertexShaderIDDX9(ShaderID *id, u32 vertType, bool useHWTransform);
|
||||
void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform);
|
||||
|
||||
// Collapse to less skinning shaders to reduce shader switching, which is expensive.
|
||||
int TranslateNumBonesDX9(int bones);
|
||||
void GenerateVertexShaderDX9(const ShaderID &id, char *buffer);
|
||||
|
||||
#define CONST_VS_PROJ 0
|
||||
#define CONST_VS_PROJ_THROUGH 4
|
||||
|
@ -292,7 +292,7 @@ void GenerateVertexShader(const ShaderID &id, char *buffer) {
|
||||
WRITE(p, "uniform highp vec2 u_fogcoef;\n");
|
||||
}
|
||||
|
||||
if (!gstate.isModeThrough() && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||
if (!isModeThrough && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||
WRITE(p, "uniform highp vec4 u_depthRange;\n");
|
||||
}
|
||||
|
||||
@ -561,7 +561,7 @@ void GenerateVertexShader(const ShaderID &id, char *buffer) {
|
||||
WRITE(p, " lightSum0.rgb += (u_lightambient%i * %s.rgb + diffuse)%s;\n", i, ambientStr, timesLightScale);
|
||||
}
|
||||
|
||||
if (id.Bit(VS_BIT_LIGHTING_ENABLE)) {
|
||||
if (enableLighting) {
|
||||
// Sum up ambient, emissive here.
|
||||
if (lmode) {
|
||||
WRITE(p, " v_color0 = clamp(lightSum0, 0.0, 1.0);\n");
|
||||
|
Loading…
Reference in New Issue
Block a user