Merge pull request #16347 from unknownbrackets/softgpu-skin

Always skin in decode for software transform and rendering
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2022-11-06 20:21:02 +01:00
commit 41c812651d
31 files changed
+104 -155

No files matched your search

+11 -7
View File
@@ -52,8 +52,7 @@ DrawEngineCommon::~DrawEngineCommon() {
}
void DrawEngineCommon::Init() {
useHWTransform_ = g_Config.bHardwareTransform;
useHWTessellation_ = UpdateUseHWTessellation(g_Config.bHardwareTessellation);
NotifyConfigChanged();
}
VertexDecoder *DrawEngineCommon::GetVertexDecoder(u32 vtype) {
@@ -169,7 +168,7 @@ static Vec3f ScreenToDrawing(const Vec3f& coords) {
return ret;
}
void DrawEngineCommon::Resized() {
void DrawEngineCommon::NotifyConfigChanged() {
decJitCache_->Clear();
lastVType_ = -1;
dec_ = nullptr;
@@ -181,10 +180,11 @@ void DrawEngineCommon::Resized() {
useHWTransform_ = g_Config.bHardwareTransform;
useHWTessellation_ = UpdateUseHWTessellation(g_Config.bHardwareTessellation);
decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning;
}
u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, u32 vertType, int *vertexSize) {
const u32 vertTypeID = (vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24);
const u32 vertTypeID = GetVertTypeID(vertType, gstate.getUVGenMode(), decOptions_.applySkinInDecode);
VertexDecoder *dec = GetVertexDecoder(vertTypeID);
if (vertexSize)
*vertexSize = dec->VertexSize();
@@ -232,7 +232,7 @@ void DrawEngineCommon::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex
}
int bytesRead;
uint32_t vertTypeID = GetVertTypeID(vtype, 0);
uint32_t vertTypeID = GetVertTypeID(vtype, 0, decOptions_.applySkinInDecode);
SubmitPrim(&temp[0], nullptr, prim, vertexCount, vertTypeID, cullMode, &bytesRead);
DispatchFlush();
@@ -280,7 +280,11 @@ bool DrawEngineCommon::TestBoundingBox(const void *control_points, const void *i
GetIndexBounds(inds, vertexCount, vertType, &indexLowerBound, &indexUpperBound);
}
// Force software skinning.
bool wasApplyingSkinInDecode = decOptions_.applySkinInDecode;
decOptions_.applySkinInDecode = true;
NormalizeVertices((u8 *)corners, temp_buffer, (const u8 *)control_points, indexLowerBound, indexUpperBound, vertType);
decOptions_.applySkinInDecode = wasApplyingSkinInDecode;
IndexConverter conv(vertType, inds);
for (int i = 0; i < vertexCount; i++) {
@@ -510,7 +514,7 @@ u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr,
};
// Let's have two separate loops, one for non skinning and one for skinning.
if (!g_Config.bSoftwareSkinning && (vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE) {
if (!dec->skinInDecode && (vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE) {
int numBoneWeights = vertTypeGetNumBoneWeights(vertType);
for (int i = lowerBound; i <= upperBound; i++) {
reader.Goto(i - lowerBound);
@@ -832,7 +836,7 @@ void DrawEngineCommon::SubmitPrim(const void *verts, const void *inds, GEPrimiti
numDrawCalls++;
vertexCountInDrawCalls_ += vertexCount;
if (g_Config.bSoftwareSkinning && (vertTypeID & GE_VTYPE_WEIGHT_MASK)) {
if (decOptions_.applySkinInDecode && (vertTypeID & GE_VTYPE_WEIGHT_MASK)) {
DecodeVertsStep(decoded, decodeCounter_, decodedVerts_);
decodeCounter_++;
}
+3 -3
View File
@@ -52,10 +52,10 @@ enum FBOTexState {
FBO_TEX_READ_FRAMEBUFFER,
};
inline uint32_t GetVertTypeID(uint32_t vertType, int uvGenMode) {
inline uint32_t GetVertTypeID(uint32_t vertType, int uvGenMode, bool skinInDecode) {
// As the decoder depends on the UVGenMode when we use UV prescale, we simply mash it
// into the top of the verttype where there are unused bits.
return (vertType & 0xFFFFFF) | (uvGenMode << 24);
return (vertType & 0xFFFFFF) | (uvGenMode << 24) | (skinInDecode << 26);
}
struct SimpleVertex;
@@ -105,7 +105,7 @@ public:
std::vector<std::string> DebugGetVertexLoaderIDs();
std::string DebugGetVertexLoaderString(std::string id, DebugShaderStringType stringType);
virtual void Resized();
virtual void NotifyConfigChanged();
bool IsCodePtrVertexDecoder(const u8 *ptr) const {
return decJitCache_->IsInSpace(ptr);
+2 -2
View File
@@ -67,7 +67,7 @@ std::string VertexShaderDesc(const VShaderID &id) {
return desc.str();
}
void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat) {
void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) {
bool isModeThrough = (vertType & GE_VTYPE_THROUGH) != 0;
bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
bool doShadeMapping = doTexture && (gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP);
@@ -118,7 +118,7 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform,
}
// Bones.
bool enableBones = vertTypeIsSkinningEnabled(vertType);
bool enableBones = !useSkinInDecode && vertTypeIsSkinningEnabled(vertType);
id.SetBit(VS_BIT_ENABLE_BONES, enableBones);
if (enableBones) {
id.SetBits(VS_BIT_BONES, 3, TranslateNumBones(vertTypeGetNumBoneWeights(vertType)) - 1);
+1 -1
View File
@@ -275,7 +275,7 @@ namespace Draw {
class Bugs;
}
void ComputeVertexShaderID(VShaderID *id, uint32_t vertexType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat);
void ComputeVertexShaderID(VShaderID *id, uint32_t vertexType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode);
// Generates a compact string that describes the shader. Useful in a list to get an overview
// of the current flora of shaders.
std::string VertexShaderDesc(const VShaderID &id);
+14 -67
View File
@@ -168,29 +168,6 @@ void SoftwareTransform::SetProjMatrix(float mtx[14], bool invertedX, bool invert
projMatrix_.translateAndScale(trans, scale);
}
static void ReadWeightedNormal(Vec3f &source, VertexReader &reader, u32 vertType, bool skinningEnabled) {
if (reader.hasNormal())
reader.ReadNrm(source.AsArray());
if (skinningEnabled) {
float weights[8];
reader.ReadWeights(weights);
// Have to recalculate this, unfortunately. Please use software skinning...
Vec3f nsum(0, 0, 0);
for (int i = 0; i < vertTypeGetNumBoneWeights(vertType); i++) {
if (weights[i] != 0.0f) {
Vec3f norm;
Norm3ByMatrix43(norm.AsArray(), source.AsArray(), gstate.boneMatrix + i * 12);
nsum += norm * weights[i];
}
}
source = nsum;
}
if (gstate.areNormalsReversed())
source = -source;
}
void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVtxFormat, int maxIndex, SoftwareTransformResult *result) {
u8 *decoded = params_.decoded;
TransformedVertex *transformed = params_.transformed;
@@ -204,8 +181,6 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt
vscale /= gstate_c.curTextureHeight;
}
bool skinningEnabled = vertTypeIsSkinningEnabled(vertType);
const int w = gstate.getTextureWidth(0);
const int h = gstate.getTextureHeight(0);
float widthFactor = (float) w / (float) gstate_c.curTextureWidth;
@@ -296,47 +271,13 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt
if (reader.hasNormal())
reader.ReadNrm(normal.AsArray());
if (!skinningEnabled) {
Vec3ByMatrix43(out, pos, gstate.worldMatrix);
if (reader.hasNormal()) {
if (gstate.areNormalsReversed()) {
normal = -normal;
}
Norm3ByMatrix43(worldnormal.AsArray(), normal.AsArray(), gstate.worldMatrix);
worldnormal = worldnormal.NormalizedOr001(cpu_info.bSSE4_1);
}
} else {
float weights[8];
// For flat, we need the vertex weights.
reader.Goto(index);
reader.ReadWeights(weights);
// Skinning
Vec3f psum(0, 0, 0);
Vec3f nsum(0, 0, 0);
for (int i = 0; i < vertTypeGetNumBoneWeights(vertType); i++) {
if (weights[i] != 0.0f) {
Vec3ByMatrix43(out, pos, gstate.boneMatrix+i*12);
Vec3f tpos(out);
psum += tpos * weights[i];
if (reader.hasNormal()) {
Vec3f norm;
Norm3ByMatrix43(norm.AsArray(), normal.AsArray(), gstate.boneMatrix+i*12);
nsum += norm * weights[i];
}
}
}
// Yes, we really must multiply by the world matrix too.
Vec3ByMatrix43(out, psum.AsArray(), gstate.worldMatrix);
if (reader.hasNormal()) {
normal = nsum;
if (gstate.areNormalsReversed()) {
normal = -normal;
}
Norm3ByMatrix43(worldnormal.AsArray(), normal.AsArray(), gstate.worldMatrix);
worldnormal = worldnormal.NormalizedOr001(cpu_info.bSSE4_1);
Vec3ByMatrix43(out, pos, gstate.worldMatrix);
if (reader.hasNormal()) {
if (gstate.areNormalsReversed()) {
normal = -normal;
}
Norm3ByMatrix43(worldnormal.AsArray(), normal.AsArray(), gstate.worldMatrix);
worldnormal = worldnormal.NormalizedOr001(cpu_info.bSSE4_1);
}
// Perform lighting here if enabled.
@@ -398,7 +339,10 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt
source = normal.Normalized(cpu_info.bSSE4_1);
} else {
reader.Goto(index);
ReadWeightedNormal(source, reader, vertType, skinningEnabled);
if (reader.hasNormal())
reader.ReadNrm(source.AsArray());
if (gstate.areNormalsReversed())
source = -source;
source.Normalize();
}
if (!reader.hasNormal()) {
@@ -413,7 +357,10 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt
} else {
// Need to read the normal for this vertex and weight it again..
reader.Goto(index);
ReadWeightedNormal(source, reader, vertType, skinningEnabled);
if (reader.hasNormal())
reader.ReadNrm(source.AsArray());
if (gstate.areNormalsReversed())
source = -source;
}
if (!reader.hasNormal()) {
ERROR_LOG_REPORT(G3D, "Normal projection mapping without normal?");
+2 -2
View File
@@ -507,7 +507,7 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic
if (indices)
GetIndexBounds(indices, num_points, vertType, &index_lower_bound, &index_upper_bound);
VertexDecoder *origVDecoder = GetVertexDecoder((vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24));
VertexDecoder *origVDecoder = GetVertexDecoder(GetVertTypeID(vertType, gstate.getUVGenMode(), decOptions_.applySkinInDecode));
*bytesRead = num_points * origVDecoder->VertexSize();
// Simplify away bones and morph before proceeding
@@ -572,7 +572,7 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic
gstate_c.uv.vOff = 0;
}
uint32_t vertTypeID = GetVertTypeID(vertTypeWithIndex16, gstate.getUVGenMode());
uint32_t vertTypeID = GetVertTypeID(vertTypeWithIndex16, gstate.getUVGenMode(), decOptions_.applySkinInDecode);
int generatedBytesRead;
if (output.count)
DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(surface.primType), output.count, vertTypeID, gstate.getCullMode(), &generatedBytesRead);
+1 -1
View File
@@ -1089,7 +1089,7 @@ void VertexDecoder::SetVertexType(u32 fmt, const VertexDecoderOptions &options,
DEBUG_LOG(G3D, "VTYPE: THRU=%i TC=%i COL=%i POS=%i NRM=%i WT=%i NW=%i IDX=%i MC=%i", (int)throughmode, tc, col, pos, nrm, weighttype, nweights, idx, morphcount);
}
skinInDecode = weighttype != 0 && g_Config.bSoftwareSkinning;
skinInDecode = weighttype != 0 && options.applySkinInDecode;
if (weighttype) { // && nweights?
weightoff = size;
+1 -2
View File
@@ -300,8 +300,6 @@ public:
bool hasNormal() const { return decFmt_.nrmfmt != 0; }
bool hasUV() const { return decFmt_.uvfmt != 0; }
bool isThrough() const { return (vtype_ & GE_VTYPE_THROUGH) != 0; }
bool skinningEnabled() const { return vertTypeIsSkinningEnabled(vtype_); }
int numBoneWeights() const { return vertTypeGetNumBoneWeights(vtype_); }
void Goto(int index) {
data_ = base_ + index * decFmt_.stride;
}
@@ -335,6 +333,7 @@ typedef void(*JittedVertexDecoder)(const u8 *src, u8 *dst, int count);
struct VertexDecoderOptions {
bool expandAllWeightsToFloat;
bool expand8BitNormalsToFloat;
bool applySkinInDecode;
};
class VertexDecoder {
+7 -5
View File
@@ -130,8 +130,8 @@ void DrawEngineD3D11::ClearInputLayoutMap() {
inputLayoutMap_.Clear();
}
void DrawEngineD3D11::Resized() {
DrawEngineCommon::Resized();
void DrawEngineD3D11::NotifyConfigChanged() {
DrawEngineCommon::NotifyConfigChanged();
ClearInputLayoutMap();
}
@@ -365,7 +365,7 @@ void DrawEngineD3D11::DoFlush() {
// Cannot cache vertex data with morph enabled.
bool useCache = g_Config.bVertexCache && !(lastVType_ & GE_VTYPE_MORPHCOUNT_MASK);
// Also avoid caching when software skinning.
if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK))
if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK))
useCache = false;
if (useCache) {
@@ -538,7 +538,7 @@ rotateVBO:
D3D11VertexShader *vshader;
D3D11FragmentShader *fshader;
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, useHWTransform, useHWTessellation_, decOptions_.expandAllWeightsToFloat);
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, useHWTransform, useHWTessellation_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode);
ID3D11InputLayout *inputLayout = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType());
context_->PSSetShader(fshader->GetShader(), nullptr, 0);
context_->VSSetShader(vshader->GetShader(), nullptr, 0);
@@ -581,6 +581,7 @@ rotateVBO:
}
} else {
PROFILE_THIS_SCOPE("soft");
decOptions_.applySkinInDecode = true;
DecodeVerts(decoded);
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
if (gstate.isModeThrough()) {
@@ -648,7 +649,7 @@ rotateVBO:
if (result.action == SW_DRAW_PRIMITIVES) {
D3D11VertexShader *vshader;
D3D11FragmentShader *fshader;
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat);
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode);
context_->PSSetShader(fshader->GetShader(), nullptr, 0);
context_->VSSetShader(vshader->GetShader(), nullptr, 0);
shaderManager_->UpdateUniforms(framebufferManager_->UseBufferedRendering());
@@ -709,6 +710,7 @@ rotateVBO:
framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor);
}
}
decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning;
}
gpuStats.numDrawCalls += numDrawCalls;
+1 -1
View File
@@ -150,7 +150,7 @@ public:
void ClearTrackedVertexArrays() override;
void Resized() override;
void NotifyConfigChanged() override;
void ClearInputLayoutMap();
+1 -1
View File
@@ -176,7 +176,7 @@ void GPU_D3D11::BeginHostFrame() {
if (resized_) {
gstate_c.useFlags = CheckGPUFeatures();
framebufferManager_->Resized();
drawEngine_.Resized();
drawEngine_.NotifyConfigChanged();
textureCache_->NotifyConfigChanged();
shaderManagerD3D11_->DirtyLastShader();
resized_ = false;
+2 -2
View File
@@ -179,13 +179,13 @@ void ShaderManagerD3D11::BindUniforms() {
context_->PSSetConstantBuffers(0, 1, ps_cbs);
}
void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat) {
void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) {
VShaderID VSID;
FShaderID FSID;
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat);
ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);
} else {
VSID = lastVSID_;
}
+1 -1
View File
@@ -85,7 +85,7 @@ public:
ShaderManagerD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context, D3D_FEATURE_LEVEL featureLevel);
~ShaderManagerD3D11();
void GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat);
void GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode);
void ClearShaders();
void DirtyLastShader() override;
+5 -3
View File
@@ -349,7 +349,7 @@ void DrawEngineDX9::DoFlush() {
// Cannot cache vertex data with morph enabled.
bool useCache = g_Config.bVertexCache && !(lastVType_ & GE_VTYPE_MORPHCOUNT_MASK);
// Also avoid caching when software skinning.
if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK))
if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK))
useCache = false;
if (useCache) {
@@ -522,7 +522,7 @@ rotateVBO:
ApplyDrawState(prim);
ApplyDrawStateLate();
VSShader *vshader = shaderManager_->ApplyShader(true, useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat, pipelineState_);
VSShader *vshader = shaderManager_->ApplyShader(true, useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode, pipelineState_);
IDirect3DVertexDeclaration9 *pHardwareVertexDecl = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType());
if (pHardwareVertexDecl) {
@@ -546,6 +546,7 @@ rotateVBO:
}
}
} else {
decOptions_.applySkinInDecode = true;
DecodeVerts(decoded);
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
if (gstate.isModeThrough()) {
@@ -613,7 +614,7 @@ rotateVBO:
ApplyDrawStateLate();
VSShader *vshader = shaderManager_->ApplyShader(false, false, lastVType_, decOptions_.expandAllWeightsToFloat, pipelineState_);
VSShader *vshader = shaderManager_->ApplyShader(false, false, lastVType_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode, pipelineState_);
if (result.action == SW_DRAW_PRIMITIVES) {
if (result.setStencil) {
@@ -653,6 +654,7 @@ rotateVBO:
framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor);
}
}
decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning;
}
gpuStats.numDrawCalls += numDrawCalls;
+2 -2
View File
@@ -165,9 +165,9 @@ void GPU_DX9::BeginHostFrame() {
if (resized_) {
gstate_c.useFlags = CheckGPUFeatures();
framebufferManager_->Resized();
drawEngine_.Resized();
shaderManagerDX9_->DirtyShader();
drawEngine_.NotifyConfigChanged();
textureCache_->NotifyConfigChanged();
shaderManagerDX9_->DirtyShader();
resized_ = false;
}
}
+3 -3
View File
@@ -544,11 +544,11 @@ void ShaderManagerDX9::DirtyLastShader() { // disables vertex arrays
lastPShader_ = nullptr;
}
VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, const ComputedPipelineState &pipelineState) {
VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, bool useSkinInDecode, const ComputedPipelineState &pipelineState) {
VShaderID VSID;
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat);
ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);
} else {
VSID = lastVSID_;
}
@@ -597,7 +597,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat
}
delete vs;
ComputeVertexShaderID(&VSID, vertType, false, false, weightsAsFloat);
ComputeVertexShaderID(&VSID, vertType, false, false, weightsAsFloat, useSkinInDecode);
// 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
+1 -1
View File
@@ -78,7 +78,7 @@ public:
~ShaderManagerDX9();
void ClearCache(bool deleteThem); // TODO: deleteThem currently not respected
VSShader *ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, const ComputedPipelineState &pipelineState);
VSShader *ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, bool useSkinInDecode, const ComputedPipelineState &pipelineState);
void DirtyShader();
void DirtyLastShader() override;
+5 -2
View File
@@ -267,7 +267,7 @@ void DrawEngineGLES::DoFlush() {
GEPrimitiveType prim = prevPrim_;
VShaderID vsid;
Shader *vshader = shaderManager_->ApplyVertexShader(CanUseHardwareTransform(prim), useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat, &vsid);
Shader *vshader = shaderManager_->ApplyVertexShader(CanUseHardwareTransform(prim), useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode, &vsid);
GLRBuffer *vertexBuffer = nullptr;
GLRBuffer *indexBuffer = nullptr;
@@ -278,7 +278,7 @@ void DrawEngineGLES::DoFlush() {
int vertexCount = 0;
bool useElements = true;
if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) {
if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) {
// If software skinning, we've already predecoded into "decoded". So push that content.
size_t size = decodedVerts_ * dec_->GetDecVtxFmt().stride;
u8 *dest = (u8 *)frameData.pushVertex->Push(size, &vertexBufferOffset, &vertexBuffer);
@@ -331,7 +331,9 @@ void DrawEngineGLES::DoFlush() {
}
} else {
PROFILE_THIS_SCOPE("soft");
decOptions_.applySkinInDecode = true;
DecodeVerts(decoded);
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
if (gstate.isModeThrough()) {
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255);
@@ -446,6 +448,7 @@ void DrawEngineGLES::DoFlush() {
}
gstate_c.Dirty(DIRTY_BLEND_STATE); // Make sure the color mask gets re-applied.
}
decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning;
}
gpuStats.numDrawCalls += numDrawCalls;
+2 -2
View File
@@ -291,9 +291,9 @@ void GPU_GLES::BeginHostFrame() {
if (resized_) {
gstate_c.useFlags = CheckGPUFeatures();
framebufferManager_->Resized();
drawEngine_.Resized();
shaderManagerGL_->DirtyShader();
drawEngine_.NotifyConfigChanged();
textureCache_->NotifyConfigChanged();
shaderManagerGL_->DirtyShader();
resized_ = false;
}
+3 -3
View File
@@ -755,10 +755,10 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) {
return new Shader(render_, codeBuffer_, desc, params);
}
Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, VShaderID *VSID) {
Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, bool useSkinInDecode, VShaderID *VSID) {
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
ComputeVertexShaderID(VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat);
ComputeVertexShaderID(VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);
} else {
*VSID = lastVSID_;
}
@@ -789,7 +789,7 @@ Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTess
// Can still work with software transform.
VShaderID vsidTemp;
ComputeVertexShaderID(&vsidTemp, vertType, false, false, weightsAsFloat);
ComputeVertexShaderID(&vsidTemp, vertType, false, false, weightsAsFloat, useSkinInDecode);
vs = CompileVertexShader(vsidTemp);
}
+1 -1
View File
@@ -161,7 +161,7 @@ public:
// This is the old ApplyShader split into two parts, because of annoying information dependencies.
// If you call ApplyVertexShader, you MUST call ApplyFragmentShader soon afterwards.
Shader *ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, VShaderID *VSID);
Shader *ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, bool useSkinInDecode, VShaderID *VSID);
LinkedShader *ApplyFragmentShader(VShaderID VSID, Shader *vs, const ComputedPipelineState &pipelineState, u32 vertType, bool useBufferedRendering);
void DeviceLost();
+2 -2
View File
@@ -1834,7 +1834,7 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) {
// cull mode
int cullMode = gstate.getCullMode();
uint32_t vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode());
uint32_t vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode(), g_Config.bSoftwareSkinning);
drawEngineCommon_->SubmitPrim(verts, inds, prim, count, vertTypeID, cullMode, &bytesRead);
// After drawing, we advance the vertexAddr (when non indexed) or indexAddr (when indexed).
// Some games rely on this, they don't bother reloading VADDR and IADDR.
@@ -1892,7 +1892,7 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) {
goto bail;
} else {
vertexType = data;
vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode());
vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode(), g_Config.bSoftwareSkinning);
}
break;
}
+1 -4
View File
@@ -261,10 +261,7 @@ void GPUgstate::Restore(u32_le *ptr) {
}
bool vertTypeIsSkinningEnabled(u32 vertType) {
if (g_Config.bSoftwareSkinning)
return false;
else
return ((vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE);
return ((vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE);
}
struct GPUStateCache_v0 {
+9 -26
View File
@@ -62,6 +62,11 @@ SoftwareDrawEngine::~SoftwareDrawEngine() {
FreeMemoryPages(decIndex, DECODED_INDEX_BUFFER_SIZE);
}
void SoftwareDrawEngine::NotifyConfigChanged() {
DrawEngineCommon::NotifyConfigChanged();
decOptions_.applySkinInDecode = true;
}
void SoftwareDrawEngine::DispatchFlush() {
transformUnit.Flush("debug");
}
@@ -72,7 +77,7 @@ void SoftwareDrawEngine::DispatchSubmitPrim(const void *verts, const void *inds,
}
void SoftwareDrawEngine::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex *buffer, int vertexCount, int cullMode, bool continuation) {
uint32_t vertTypeID = GetVertTypeID(gstate.vertType | GE_VTYPE_POS_FLOAT, gstate.getUVGenMode());
uint32_t vertTypeID = GetVertTypeID(gstate.vertType | GE_VTYPE_POS_FLOAT, gstate.getUVGenMode(), true);
int flipCull = cullMode != gstate.getCullMode() ? 1 : 0;
// TODO: For now, just setting all dirty.
@@ -137,7 +142,7 @@ void SoftwareDrawEngine::DispatchSubmitImm(GEPrimitiveType prim, TransformedVert
}
VertexDecoder *SoftwareDrawEngine::FindVertexDecoder(u32 vtype) {
const u32 vertTypeID = (vtype & 0xFFFFFF) | (gstate.getUVGenMode() << 24);
const u32 vertTypeID = GetVertTypeID(vtype, gstate.getUVGenMode(), true);
return DrawEngineCommon::GetVertexDecoder(vertTypeID);
}
@@ -245,7 +250,6 @@ struct TransformState {
bool enableLighting : 1;
bool enableFog : 1;
bool readUV : 1;
bool readWeights : 1;
bool negateNormals : 1;
uint8_t uvGenMode : 2;
uint8_t matrixMode : 2;
@@ -257,7 +261,6 @@ void ComputeTransformState(TransformState *state, const VertexReader &vreader) {
state->enableLighting = gstate.isLightingEnabled();
state->enableFog = gstate.isFogEnabled();
state->readUV = !gstate.isModeClear() && gstate.isTextureMapEnabled() && vreader.hasUV();
state->readWeights = vreader.skinningEnabled() && state->enableTransform;
state->negateNormals = gstate.areNormalsReversed();
state->uvGenMode = gstate.getUVGenMode();
@@ -344,27 +347,6 @@ ClipVertexData TransformUnit::ReadVertex(VertexReader &vreader, const TransformS
if (state.negateNormals)
normal = -normal;
if (state.readWeights) {
float W[8] = { 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f };
vreader.ReadWeights(W);
Vec3<float> tmppos(0.f, 0.f, 0.f);
Vec3<float> tmpnrm(0.f, 0.f, 0.f);
for (int i = 0; i < vreader.numBoneWeights(); ++i) {
Vec3<float> step = Vec3ByMatrix43(pos, gstate.boneMatrix + i * 12);
tmppos += step * W[i];
if (vreader.hasNormal()) {
step = Norm3ByMatrix43(normal, gstate.boneMatrix + i * 12);
tmpnrm += step * W[i];
}
}
pos = tmppos;
if (vreader.hasNormal())
normal = tmpnrm;
}
if (vreader.hasColor0()) {
vreader.ReadColor0_8888((u8 *)&vertex.v.color0);
} else {
@@ -858,7 +840,7 @@ void TransformUnit::SubmitImmVertex(const ClipVertexData &vert, SoftwareDrawEngi
break;
}
uint32_t vertTypeID = GetVertTypeID(gstate.vertType | GE_VTYPE_POS_FLOAT, gstate.getUVGenMode());
uint32_t vertTypeID = GetVertTypeID(gstate.vertType | GE_VTYPE_POS_FLOAT, gstate.getUVGenMode(), true);
// 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);
@@ -958,6 +940,7 @@ bool TransformUnit::GetCurrentSimpleVertices(int count, std::vector<GPUDebugVert
VertexDecoder vdecoder;
VertexDecoderOptions options{};
options.applySkinInDecode = true;
vdecoder.SetVertexType(gstate.vertType, options);
if (!Memory::IsValidRange(gstate_c.vertexAddr, (indexUpperBound + 1) * vdecoder.VertexSize()))
+1
View File
@@ -171,6 +171,7 @@ public:
SoftwareDrawEngine();
~SoftwareDrawEngine();
void NotifyConfigChanged() override;
void DispatchFlush() override;
void DispatchSubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int cullMode, int *bytesRead) override;
void DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex *buffer, int vertexCount, int cullMode, bool continuation) override;
+7 -4
View File
@@ -599,7 +599,7 @@ void DrawEngineVulkan::DoFlush() {
// Also avoid caching when software skinning.
VkBuffer vbuf = VK_NULL_HANDLE;
VkBuffer ibuf = VK_NULL_HANDLE;
if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) {
if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) {
useCache = false;
}
@@ -739,7 +739,7 @@ void DrawEngineVulkan::DoFlush() {
break;
}
} else {
if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) {
if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) {
// If software skinning, we've already predecoded into "decoded". So push that content.
VkDeviceSize size = decodedVerts_ * dec_->GetDecVtxFmt().stride;
u8 *dest = (u8 *)frameData.pushVertex->Push(size, &vbOffset, &vbuf);
@@ -784,7 +784,7 @@ void DrawEngineVulkan::DoFlush() {
VulkanFragmentShader *fshader = nullptr;
VulkanGeometryShader *gshader = nullptr;
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat); // usehwtransform
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode);
if (!vshader) {
// We're screwed.
return;
@@ -841,6 +841,7 @@ void DrawEngineVulkan::DoFlush() {
}
} else {
PROFILE_THIS_SCOPE("soft");
decOptions_.applySkinInDecode = true;
DecodeVerts(decoded);
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
if (gstate.isModeThrough()) {
@@ -919,7 +920,7 @@ void DrawEngineVulkan::DoFlush() {
VulkanFragmentShader *fshader = nullptr;
VulkanGeometryShader *gshader = nullptr;
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat); // usehwtransform
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode);
_dbg_assert_msg_(!vshader->UseHWTransform(), "Bad vshader");
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, false, 0);
if (!pipeline || !pipeline->pipeline) {
@@ -927,6 +928,7 @@ void DrawEngineVulkan::DoFlush() {
decodedVerts_ = 0;
numDrawCalls = 0;
decodeCounter_ = 0;
decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning;
return;
}
BindShaderBlendTex(); // This might cause copies so super important to do before BindPipeline.
@@ -994,6 +996,7 @@ void DrawEngineVulkan::DoFlush() {
framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, result.color);
}
}
decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning;
}
gpuStats.numDrawCalls += numDrawCalls;
+1 -1
View File
@@ -292,7 +292,7 @@ void GPU_Vulkan::BeginHostFrame() {
// In case the GPU changed.
BuildReportingInfo();
framebufferManager_->Resized();
drawEngine_.Resized();
drawEngine_.NotifyConfigChanged();
textureCache_->NotifyConfigChanged();
resized_ = false;
}
+2 -2
View File
@@ -280,11 +280,11 @@ uint64_t ShaderManagerVulkan::UpdateUniforms(bool useBufferedRendering) {
return dirty;
}
void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat) {
void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) {
VShaderID VSID;
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat);
ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);
} else {
VSID = lastVSID_;
}
+1 -1
View File
@@ -115,7 +115,7 @@ public:
void DeviceLost();
void DeviceRestore(Draw::DrawContext *draw);
void GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat);
void GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode);
void ClearShaders();
void DirtyShader();
void DirtyLastShader() override;
+2
View File
@@ -306,6 +306,8 @@ int CtrlVertexList::GetRowCount() {
rowCount_ = 0;
}
VertexDecoderOptions options{};
// TODO: Maybe an option?
options.applySkinInDecode = true;
decoder->SetVertexType(state.vertType, options);
return rowCount_;
}
+9 -3
View File
@@ -545,8 +545,10 @@ static bool TestVertexColor565() {
static bool TestVertex8Skin() {
VertexDecoderTestHarness dec;
VertexDecoderOptions opts{};
opts.applySkinInDecode = true;
dec.SetOptions(opts);
g_Config.bSoftwareSkinning = true;
for (int i = 0; i < 8 * 12; ++i) {
gstate.boneMatrix[i] = 0.0f;
}
@@ -575,8 +577,10 @@ static bool TestVertex8Skin() {
static bool TestVertex16Skin() {
VertexDecoderTestHarness dec;
VertexDecoderOptions opts{};
opts.applySkinInDecode = true;
dec.SetOptions(opts);
g_Config.bSoftwareSkinning = true;
for (int i = 0; i < 8 * 12; ++i) {
gstate.boneMatrix[i] = 0.0f;
}
@@ -605,8 +609,10 @@ static bool TestVertex16Skin() {
static bool TestVertexFloatSkin() {
VertexDecoderTestHarness dec;
VertexDecoderOptions opts{};
opts.applySkinInDecode = true;
dec.SetOptions(opts);
g_Config.bSoftwareSkinning = true;
for (int i = 0; i < 8 * 12; ++i) {
gstate.boneMatrix[i] = 0.0f;
}