diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 8724325f17..502d115b53 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -133,11 +133,10 @@ void DrawEngineCommon::NotifyConfigChanged() { 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 = GetVertTypeID(vertType, gstate.getUVGenMode(), decOptions_.applySkinInDecode); + const u32 vertTypeID = GetVertTypeID(vertType, gstate.getUVGenMode(), applySkinInDecode_); VertexDecoder *dec = GetVertexDecoder(vertTypeID); if (vertexSize) *vertexSize = dec->VertexSize(); @@ -185,7 +184,7 @@ void DrawEngineCommon::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex } int bytesRead; - uint32_t vertTypeID = GetVertTypeID(vtype, 0, decOptions_.applySkinInDecode); + uint32_t vertTypeID = GetVertTypeID(vtype, 0, applySkinInDecode_); bool clockwise = !gstate.isCullEnabled() || gstate.getCullMode() == cullMode; SubmitPrim(&temp[0], nullptr, prim, vertexCount, vertTypeID, clockwise, &bytesRead); @@ -303,10 +302,10 @@ bool DrawEngineCommon::TestBoundingBox(const void *vdata, const void *inds, int } // TODO: Avoid normalization if just plain skinning. // Force software skinning. - bool wasApplyingSkinInDecode = decOptions_.applySkinInDecode; - decOptions_.applySkinInDecode = true; + bool wasApplyingSkinInDecode = applySkinInDecode_; + applySkinInDecode_ = true; NormalizeVertices((u8 *)corners, temp_buffer, (const u8 *)vdata, indexLowerBound, indexUpperBound, vertType); - decOptions_.applySkinInDecode = wasApplyingSkinInDecode; + applySkinInDecode_ = wasApplyingSkinInDecode; IndexConverter conv(vertType, inds); for (int i = 0; i < vertexCount; i++) { @@ -985,7 +984,7 @@ bool DrawEngineCommon::SubmitPrim(const void *verts, const void *inds, GEPrimiti } } - bool applySkin = (vertTypeID & GE_VTYPE_WEIGHT_MASK) && decOptions_.applySkinInDecode; + bool applySkin = dec_->skinInDecode; DeferredInds &di = drawInds_[numDrawInds_++]; di.inds = inds; @@ -1038,10 +1037,17 @@ bool DrawEngineCommon::SubmitPrim(const void *verts, const void *inds, GEPrimiti return true; } -void DrawEngineCommon::DecodeVerts(u8 *dest) { +void DrawEngineCommon::BeginFrame() { + applySkinInDecode_ = g_Config.bSoftwareSkinning; +} + +void DrawEngineCommon::DecodeVerts(VertexDecoder *dec, u8 *dest) { + if (!numDrawVerts_) { + return; + } // Note that this should be able to continue a partial decode - we don't necessarily start from zero here (although we do most of the time). int i = decodeVertsCounter_; - int stride = (int)dec_->GetDecVtxFmt().stride; + int stride = (int)dec->GetDecVtxFmt().stride; for (; i < numDrawVerts_; i++) { DeferredVerts &dv = drawVerts_[i]; @@ -1056,7 +1062,7 @@ void DrawEngineCommon::DecodeVerts(u8 *dest) { } // Decode the verts (and at the same time apply morphing/skinning). Simple. - dec_->DecodeVerts(dest + numDecodedVerts_ * stride, dv.verts, &dv.uvScale, indexLowerBound, indexUpperBound); + dec->DecodeVerts(dest + numDecodedVerts_ * stride, dv.verts, &dv.uvScale, indexLowerBound, indexUpperBound); numDecodedVerts_ += indexUpperBound - indexLowerBound + 1; } decodeVertsCounter_ = i; diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 7b236da599..c8733ecbaa 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -53,12 +53,6 @@ enum FBOTexState { FBO_TEX_READ_FRAMEBUFFER, }; -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) | (skinInDecode << 26); -} - struct SimpleVertex; namespace Spline { struct Weight2D; } @@ -83,6 +77,8 @@ public: void Init(); + virtual void BeginFrame(); + void SetGPUCommon(GPUCommon *gpuCommon) { gpuCommon_ = gpuCommon; } @@ -114,9 +110,8 @@ public: bool TestBoundingBoxThrough(const void *vdata, int vertexCount, u32 vertType); void FlushSkin() { - bool applySkin = (lastVType_ & GE_VTYPE_WEIGHT_MASK) && decOptions_.applySkinInDecode; - if (applySkin) { - DecodeVerts(decoded_); + if (dec_->skinInDecode) { + DecodeVerts(dec_, decoded_); } } @@ -160,7 +155,7 @@ protected: virtual bool UpdateUseHWTessellation(bool enabled) const { return enabled; } void UpdatePlanes(); - void DecodeVerts(u8 *dest); + void DecodeVerts(VertexDecoder *dec, u8 *dest); int DecodeInds(); // Preprocessing for spline/bezier @@ -314,6 +309,8 @@ protected: bool anyCCWOrIndexed_ = 0; bool anyIndexed_ = 0; + bool applySkinInDecode_ = false; + // Vertex collector state IndexGenerator indexGen; int numDecodedVerts_ = 0; diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 9100e0b21e..06bebe5617 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -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(GetVertTypeID(vertType, gstate.getUVGenMode(), decOptions_.applySkinInDecode)); + VertexDecoder *origVDecoder = GetVertexDecoder(GetVertTypeID(vertType, gstate.getUVGenMode(), applySkinInDecode_)); *bytesRead = num_points * origVDecoder->VertexSize(); // Simplify away bones and morph before proceeding @@ -574,7 +574,7 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic gstate_c.uv.vOff = 0; } - uint32_t vertTypeID = GetVertTypeID(vertTypeWithIndex16, gstate.getUVGenMode(), decOptions_.applySkinInDecode); + uint32_t vertTypeID = GetVertTypeID(vertTypeWithIndex16, gstate.getUVGenMode(), applySkinInDecode_); int generatedBytesRead; if (output.count) DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(surface.primType), output.count, vertTypeID, true, &generatedBytesRead); diff --git a/GPU/Common/VertexDecoderCommon.cpp b/GPU/Common/VertexDecoderCommon.cpp index 9885aa0069..ef26be2f96 100644 --- a/GPU/Common/VertexDecoderCommon.cpp +++ b/GPU/Common/VertexDecoderCommon.cpp @@ -1125,7 +1125,7 @@ void VertexDecoder::SetVertexType(u32 fmt, const VertexDecoderOptions &options, DEBUG_LOG(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 && options.applySkinInDecode; + skinInDecode = weighttype != 0 && VertTypeIDSkinInDecode(fmt); if (weighttype) { // && nweights? weightoff = size; @@ -1182,7 +1182,8 @@ void VertexDecoder::SetVertexType(u32 fmt, const VertexDecoderOptions &options, // NOTE: That we check getUVGenMode here means that we must include it in the decoder ID! // throughmode is automatically included though, because it's part of the vertType. - if (!throughmode && (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_COORDS || gstate.getUVGenMode() == GE_TEXMAP_UNKNOWN)) { + GETexMapMode mode = VertTypeIDUVGenMode(fmt); + if (!throughmode && (mode == GE_TEXMAP_TEXTURE_COORDS || mode == GE_TEXMAP_UNKNOWN)) { if (g_DoubleTextureCoordinates) steps_[numSteps_++] = morphcount == 1 ? tcstep_prescale_remaster[tc] : tcstep_prescale_morph_remaster[tc]; else diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index 7a40701e01..2793ad80ee 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -325,9 +325,22 @@ typedef void (*JittedVertexDecoder)(const u8 *src, u8 *dst, int count, const UVS struct VertexDecoderOptions { bool expandAllWeightsToFloat; bool expand8BitNormalsToFloat; - bool applySkinInDecode; }; +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) | (skinInDecode << 26); +} + +inline bool VertTypeIDSkinInDecode(uint32_t vertType) { + return ((vertType >> 26) & 1) != 0; +} + +inline GETexMapMode VertTypeIDUVGenMode(uint32_t vertType) { + return (GETexMapMode)((vertType >> 24) & 3); +} + class VertexDecoder { public: // A jit cache is not mandatory. @@ -512,7 +525,6 @@ public: // Returns a pointer to the code to run. JittedVertexDecoder Compile(const VertexDecoder &dec, int32_t *jittedSize); - bool DescribeCodePtr(const u8 *ptr, std::string &name) const; void Clear(); void Jit_WeightsU8(); diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 2d6a372830..4ad2b8bf51 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -239,6 +239,8 @@ ID3D11InputLayout *DrawEngineD3D11::SetupDecFmtForDraw(D3D11VertexShader *vshade } void DrawEngineD3D11::BeginFrame() { + DrawEngineCommon::BeginFrame(); + pushVerts_->Reset(); pushInds_->Reset(); @@ -282,7 +284,7 @@ void DrawEngineD3D11::Flush() { int vertexCount; int maxIndex; bool useElements; - DecodeVerts(decoded_); + DecodeVerts(dec_, decoded_); DecodeIndsAndGetData(&prim, &vertexCount, &maxIndex, &useElements, false); gpuStats.numUncachedVertsDrawn += vertexCount; @@ -303,7 +305,7 @@ void DrawEngineD3D11::Flush() { D3D11VertexShader *vshader; D3D11FragmentShader *fshader; - shaderManager_->GetShaders(prim, dec_, &vshader, &fshader, pipelineState_, useHWTransform, useHWTessellation_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode); + shaderManager_->GetShaders(prim, dec_, &vshader, &fshader, pipelineState_, useHWTransform, useHWTessellation_, decOptions_.expandAllWeightsToFloat, applySkinInDecode_); ID3D11InputLayout *inputLayout = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType()); context_->PSSetShader(fshader->GetShader(), nullptr, 0); context_->VSSetShader(vshader->GetShader(), nullptr, 0); @@ -346,12 +348,15 @@ void DrawEngineD3D11::Flush() { } } else { PROFILE_THIS_SCOPE("soft"); - if (!decOptions_.applySkinInDecode) { - decOptions_.applySkinInDecode = true; - lastVType_ |= (1 << 26); - dec_ = GetVertexDecoder(lastVType_); + VertexDecoder *swDec = dec_; + if (swDec->nweights != 0) { + u32 withSkinning = lastVType_ | (1 << 26); + if (withSkinning != lastVType_) { + swDec = GetVertexDecoder(withSkinning); + } } - DecodeVerts(decoded_); + + DecodeVerts(swDec, decoded_); int vertexCount = DecodeInds(); bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; @@ -400,7 +405,7 @@ void DrawEngineD3D11::Flush() { const Lin::Vec3 scale(gstate_c.vpWidthScale, -gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight < 0, trans, scale); - swTransform.Transform(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), numDecodedVerts_, &result); + swTransform.Transform(prim, swDec->VertexType(), swDec->GetDecVtxFmt(), numDecodedVerts_, &result); // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) @@ -416,7 +421,7 @@ void DrawEngineD3D11::Flush() { ApplyDrawState(prim); if (result.action == SW_NOT_READY) - swTransform.BuildDrawingParams(prim, vertexCount, dec_->VertexType(), inds, RemainingIndices(inds), numDecodedVerts_, VERTEX_BUFFER_MAX, &result); + swTransform.BuildDrawingParams(prim, vertexCount, swDec->VertexType(), inds, RemainingIndices(inds), numDecodedVerts_, VERTEX_BUFFER_MAX, &result); if (result.setSafeSize) framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); @@ -425,7 +430,7 @@ void DrawEngineD3D11::Flush() { if (result.action == SW_DRAW_INDEXED) { D3D11VertexShader *vshader; D3D11FragmentShader *fshader; - shaderManager_->GetShaders(prim, dec_, &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true); + shaderManager_->GetShaders(prim, swDec, &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true); context_->PSSetShader(fshader->GetShader(), nullptr, 0); context_->VSSetShader(vshader->GetShader(), nullptr, 0); shaderManager_->UpdateUniforms(framebufferManager_->UseBufferedRendering()); @@ -478,7 +483,6 @@ void DrawEngineD3D11::Flush() { framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor); } } - decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; } ResetAfterDrawInline(); diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index d870ae1850..1b69736d13 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -75,12 +75,12 @@ public: void InitDeviceObjects(); void DestroyDeviceObjects(); - void BeginFrame(); + void BeginFrame() override; void Flush() override; void FinishDeferred() { - DecodeVerts(decoded_); + DecodeVerts(dec_, decoded_); } void NotifyConfigChanged() override; diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index 6cc0618a24..d557148beb 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -219,6 +219,7 @@ static uint32_t SwapRB(uint32_t c) { } void DrawEngineDX9::BeginFrame() { + DrawEngineCommon::BeginFrame(); lastRenderStepId_ = -1; } @@ -256,7 +257,7 @@ void DrawEngineDX9::Flush() { int vertexCount; int maxIndex; bool useElements; - DecodeVerts(decoded_); + DecodeVerts(dec_, decoded_); DecodeIndsAndGetData(&prim, &vertexCount, &maxIndex, &useElements, false); gpuStats.numUncachedVertsDrawn += vertexCount; @@ -276,7 +277,7 @@ void DrawEngineDX9::Flush() { ApplyDrawState(prim); ApplyDrawStateLate(); - VSShader *vshader = shaderManager_->ApplyShader(true, useHWTessellation_, dec_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode, pipelineState_); + VSShader *vshader = shaderManager_->ApplyShader(true, useHWTessellation_, dec_, decOptions_.expandAllWeightsToFloat, applySkinInDecode_, pipelineState_); ComPtr pHardwareVertexDecl; SetupDecFmtForDraw(dec_->GetDecVtxFmt(), dec_->VertexType(), &pHardwareVertexDecl); @@ -301,12 +302,14 @@ void DrawEngineDX9::Flush() { } } } else { - if (!decOptions_.applySkinInDecode) { - decOptions_.applySkinInDecode = true; - lastVType_ |= (1 << 26); - dec_ = GetVertexDecoder(lastVType_); + VertexDecoder *swDec = dec_; + if (swDec->nweights != 0) { + u32 withSkinning = lastVType_ | (1 << 26); + if (withSkinning != lastVType_) { + swDec = GetVertexDecoder(withSkinning); + } } - DecodeVerts(decoded_); + DecodeVerts(swDec, decoded_); int vertexCount = DecodeInds(); bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; @@ -361,7 +364,7 @@ void DrawEngineDX9::Flush() { const Lin::Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight > 0, trans, scale); - swTransform.Transform(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), numDecodedVerts_, &result); + swTransform.Transform(prim, swDec->VertexType(), swDec->GetDecVtxFmt(), numDecodedVerts_, &result); // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) @@ -376,13 +379,13 @@ void DrawEngineDX9::Flush() { ApplyDrawState(prim); if (result.action == SW_NOT_READY) - swTransform.BuildDrawingParams(prim, vertexCount, dec_->VertexType(), inds, RemainingIndices(inds), numDecodedVerts_, VERTEX_BUFFER_MAX, &result); + swTransform.BuildDrawingParams(prim, vertexCount, swDec->VertexType(), inds, RemainingIndices(inds), numDecodedVerts_, VERTEX_BUFFER_MAX, &result); if (result.setSafeSize) framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); ApplyDrawStateLate(); - VSShader *vshader = shaderManager_->ApplyShader(false, false, dec_, decOptions_.expandAllWeightsToFloat, true, pipelineState_); + VSShader *vshader = shaderManager_->ApplyShader(false, false, swDec, decOptions_.expandAllWeightsToFloat, true, pipelineState_); if (result.action == SW_DRAW_INDEXED) { if (result.setStencil) { @@ -414,7 +417,6 @@ void DrawEngineDX9::Flush() { framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor); } } - decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; } ResetAfterDrawInline(); diff --git a/GPU/Directx9/DrawEngineDX9.h b/GPU/Directx9/DrawEngineDX9.h index 6bbf6ffcab..9165955c6f 100644 --- a/GPU/Directx9/DrawEngineDX9.h +++ b/GPU/Directx9/DrawEngineDX9.h @@ -65,13 +65,13 @@ public: void InitDeviceObjects(); void DestroyDeviceObjects(); - void BeginFrame(); + void BeginFrame() override; // So that this can be inlined void Flush() override; void FinishDeferred() { - DecodeVerts(decoded_); + DecodeVerts(dec_, decoded_); } protected: diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 7d2e7cce0e..d96631174c 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -147,6 +147,8 @@ void DrawEngineGLES::ClearInputLayoutMap() { } void DrawEngineGLES::BeginFrame() { + DrawEngineCommon::BeginFrame(); + FrameData &frameData = frameData_[render_->GetCurFrame()]; frameData.pushIndex->Begin(); frameData.pushVertex->Begin(); @@ -264,7 +266,7 @@ void DrawEngineGLES::Flush() { GEPrimitiveType prim = prevPrim_; - Shader *vshader = shaderManager_->ApplyVertexShader(CanUseHardwareTransform(prim), useHWTessellation_, dec_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode || !CanUseHardwareTransform(prim), &vsid); + Shader *vshader = shaderManager_->ApplyVertexShader(CanUseHardwareTransform(prim), useHWTessellation_, dec_, decOptions_.expandAllWeightsToFloat, applySkinInDecode_ || !CanUseHardwareTransform(prim), &vsid); GLRBuffer *vertexBuffer = nullptr; GLRBuffer *indexBuffer = nullptr; @@ -272,9 +274,9 @@ void DrawEngineGLES::Flush() { uint32_t indexBufferOffset = 0; if (vshader->UseHWTransform()) { - if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) { + if (applySkinInDecode_ && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) { // If software skinning, we're predecoding into "decoded". So make sure we're done, then push that content. - DecodeVerts(decoded_); + DecodeVerts(dec_, decoded_); uint32_t size = numDecodedVerts_ * dec_->GetDecVtxFmt().stride; u8 *dest = (u8 *)frameData.pushVertex->Allocate(size, 4, &vertexBuffer, &vertexBufferOffset); memcpy(dest, decoded_, size); @@ -282,13 +284,13 @@ void DrawEngineGLES::Flush() { // Figure out how much pushbuffer space we need to allocate. int vertsToDecode = ComputeNumVertsToDecode(); u8 *dest = (u8 *)frameData.pushVertex->Allocate(vertsToDecode * dec_->GetDecVtxFmt().stride, 4, &vertexBuffer, &vertexBufferOffset); - DecodeVerts(dest); + DecodeVerts(dec_, dest); } int vertexCount; int maxIndex; bool useElements; - DecodeVerts(decoded_); + DecodeVerts(dec_, decoded_); DecodeIndsAndGetData(&prim, &vertexCount, &maxIndex, &useElements, false); if (useElements) { @@ -328,12 +330,14 @@ void DrawEngineGLES::Flush() { } } else { PROFILE_THIS_SCOPE("soft"); - if (!decOptions_.applySkinInDecode) { - decOptions_.applySkinInDecode = true; - lastVType_ |= (1 << 26); - dec_ = GetVertexDecoder(lastVType_); + VertexDecoder *swDec = dec_; + if (swDec->nweights != 0) { + u32 withSkinning = lastVType_ | (1 << 26); + if (withSkinning != lastVType_) { + swDec = GetVertexDecoder(withSkinning); + } } - DecodeVerts(decoded_); + DecodeVerts(swDec, decoded_); int vertexCount = DecodeInds(); bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; @@ -387,7 +391,7 @@ void DrawEngineGLES::Flush() { const bool invertedY = gstate_c.vpHeight * (params.flippedY ? 1.0 : -1.0f) < 0; swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, invertedY, trans, scale); - swTransform.Transform(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), numDecodedVerts_, &result); + swTransform.Transform(prim, swDec->VertexType(), swDec->GetDecVtxFmt(), numDecodedVerts_, &result); // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) @@ -403,7 +407,7 @@ void DrawEngineGLES::Flush() { ApplyDrawState(prim); if (result.action == SW_NOT_READY) - swTransform.BuildDrawingParams(prim, vertexCount, dec_->VertexType(), inds, RemainingIndices(inds), numDecodedVerts_, VERTEX_BUFFER_MAX, &result); + swTransform.BuildDrawingParams(prim, vertexCount, swDec->VertexType(), inds, RemainingIndices(inds), numDecodedVerts_, VERTEX_BUFFER_MAX, &result); if (result.setSafeSize) framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); @@ -447,7 +451,6 @@ void DrawEngineGLES::Flush() { } gstate_c.Dirty(DIRTY_BLEND_STATE); // Make sure the color mask gets re-applied. } - decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; } bail: diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index 167635af5a..9d05fdb429 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -81,7 +81,7 @@ public: void ClearTrackedVertexArrays() override {} - void BeginFrame(); + void BeginFrame() override; void EndFrame(); // So that this can be inlined diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 12a520b30f..ea03a5b360 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -63,7 +63,7 @@ SoftwareDrawEngine::~SoftwareDrawEngine() {} void SoftwareDrawEngine::NotifyConfigChanged() { DrawEngineCommon::NotifyConfigChanged(); - decOptions_.applySkinInDecode = true; + applySkinInDecode_ = true; } void SoftwareDrawEngine::Flush() { @@ -973,8 +973,8 @@ bool TransformUnit::GetCurrentSimpleVertices(int count, std::vectorGetDecVtxFmt().stride; u8 *dest = (u8 *)pushVertex_->Allocate(size, 4, &vbuf, &vbOffset); memcpy(dest, decoded_, size); @@ -269,7 +271,7 @@ void DrawEngineVulkan::Flush() { int vertsToDecode = ComputeNumVertsToDecode(); // Decode directly into the pushbuffer u8 *dest = pushVertex_->Allocate(vertsToDecode * dec_->GetDecVtxFmt().stride, 4, &vbuf, &vbOffset); - DecodeVerts(dest); + DecodeVerts(dec_, dest); } int vertexCount; @@ -302,7 +304,7 @@ void DrawEngineVulkan::Flush() { VulkanFragmentShader *fshader = nullptr; VulkanGeometryShader *gshader = nullptr; - shaderManager_->GetShaders(prim, dec_, &vshader, &fshader, &gshader, pipelineState_, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode); + shaderManager_->GetShaders(prim, dec_, &vshader, &fshader, &gshader, pipelineState_, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat, applySkinInDecode_); _dbg_assert_msg_(vshader->UseHWTransform(), "Bad vshader"); VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, true, 0, framebufferManager_->GetMSAALevel(), false); if (!pipeline || !pipeline->pipeline) { @@ -381,14 +383,16 @@ void DrawEngineVulkan::Flush() { } } else { PROFILE_THIS_SCOPE("soft"); - if (!decOptions_.applySkinInDecode) { - decOptions_.applySkinInDecode = true; - lastVType_ |= (1 << 26); - dec_ = GetVertexDecoder(lastVType_); + VertexDecoder *swDec = dec_; + if (swDec->nweights != 0) { + u32 withSkinning = lastVType_ | (1 << 26); + if (withSkinning != lastVType_) { + swDec = GetVertexDecoder(withSkinning); + } } int prevDecodedVerts = numDecodedVerts_; - DecodeVerts(decoded_); + DecodeVerts(swDec, decoded_); int vertexCount = DecodeInds(); bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; @@ -444,7 +448,7 @@ void DrawEngineVulkan::Flush() { const Lin::Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight < 0, trans, scale); - swTransform.Transform(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), numDecodedVerts_, &result); + swTransform.Transform(prim, swDec->VertexType(), swDec->GetDecVtxFmt(), numDecodedVerts_, &result); // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) @@ -452,7 +456,7 @@ void DrawEngineVulkan::Flush() { if (result.action == SW_NOT_READY) { // decIndex_ here is always equal to inds currently, but it may not be in the future. - swTransform.BuildDrawingParams(prim, vertexCount, dec_->VertexType(), inds, RemainingIndices(inds), numDecodedVerts_, VERTEX_BUFFER_MAX, &result); + swTransform.BuildDrawingParams(prim, vertexCount, swDec->VertexType(), inds, RemainingIndices(inds), numDecodedVerts_, VERTEX_BUFFER_MAX, &result); } if (result.setSafeSize) @@ -480,9 +484,9 @@ void DrawEngineVulkan::Flush() { VulkanFragmentShader *fshader = nullptr; VulkanGeometryShader *gshader = nullptr; - shaderManager_->GetShaders(prim, dec_, &vshader, &fshader, &gshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true); + shaderManager_->GetShaders(prim, swDec, &vshader, &fshader, &gshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true); _dbg_assert_msg_(!vshader->UseHWTransform(), "Bad vshader"); - VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, false, 0, framebufferManager_->GetMSAALevel(), false); + VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &swDec->decFmt, vshader, fshader, gshader, false, 0, framebufferManager_->GetMSAALevel(), false); if (!pipeline || !pipeline->pipeline) { // Already logged, let's bail out. ResetAfterDraw(); @@ -563,7 +567,6 @@ void DrawEngineVulkan::Flush() { framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, result.color); } } - decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; } ResetAfterDrawInline(); @@ -581,7 +584,6 @@ void DrawEngineVulkan::ResetAfterDraw() { vertexCountInDrawCalls_ = 0; decodeIndsCounter_ = 0; decodeVertsCounter_ = 0; - decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; gstate_c.vertexFullAlpha = true; } diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index 185f66f9a2..2d7aceaf90 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -136,7 +136,7 @@ public: return pipelineLayout_; } - void BeginFrame(); + void BeginFrame() override; void EndFrame(); void DirtyAllUBOs(); diff --git a/UI/ImDebugger/ImGe.cpp b/UI/ImDebugger/ImGe.cpp index e2c14320ec..d9e2159437 100644 --- a/UI/ImDebugger/ImGe.cpp +++ b/UI/ImDebugger/ImGe.cpp @@ -1360,15 +1360,13 @@ void ImGeStateWindow::Draw(ImConfig &cfg, ImControl &control, GPUDebugInterface if (!gpuDebug->GetCurrentSimpleVertices(rowCount_, vertices, indices)) { rowCount_ = 0; } - VertexDecoderOptions options{}; - // TODO: Maybe an option? - options.applySkinInDecode = true; - auto buildVertexTable = [&](bool raw) { // Ignore indices for now. if (ImGui::BeginTable("rawverts", VERTEXLIST_COL_COUNT + 1, tableFlags)) { static VertexDecoder decoder; - decoder.SetVertexType(state.vertType, options); + u32 vertTypeID = GetVertTypeID(state.vertType, state.getUVGenMode(), true); + VertexDecoderOptions options{}; + decoder.SetVertexType(vertTypeID, options); static const char * const colNames[] = { "Index", diff --git a/Windows/GEDebugger/TabVertices.cpp b/Windows/GEDebugger/TabVertices.cpp index 464471398e..0091d358a6 100644 --- a/Windows/GEDebugger/TabVertices.cpp +++ b/Windows/GEDebugger/TabVertices.cpp @@ -175,8 +175,8 @@ int CtrlVertexList::GetRowCount() { } VertexDecoderOptions options{}; // TODO: Maybe an option? - options.applySkinInDecode = true; - decoder->SetVertexType(state.vertType, options); + u32 vertTypeID = GetVertTypeID(state.vertType, state.getUVGenMode(), true); + decoder->SetVertexType(vertTypeID, options); return rowCount_; } diff --git a/unittest/TestVertexJit.cpp b/unittest/TestVertexJit.cpp index f5561c0fa9..cd6dc5625d 100644 --- a/unittest/TestVertexJit.cpp +++ b/unittest/TestVertexJit.cpp @@ -51,7 +51,7 @@ public: void Reset() { memset(src_, 0, BUFFER_SIZE); memset(dst_, 0, BUFFER_SIZE); - memset(&options_, 0, sizeof(options_)); + options_ = {}; delete dec_; dec_ = nullptr; indexLowerBound_ = 0; @@ -65,7 +65,7 @@ public: if (needsReset_) { Reset(); } - memcpy(&options_, &opts, sizeof(options_)); + options_ = opts; } void SetIndexLowerBound(const int lower) { @@ -543,7 +543,6 @@ static bool TestVertexColor565() { static bool TestVertex8Skin() { VertexDecoderTestHarness dec; VertexDecoderOptions opts{}; - opts.applySkinInDecode = true; dec.SetOptions(opts); for (int i = 0; i < 8 * 12; ++i) { @@ -558,13 +557,14 @@ static bool TestVertex8Skin() { gstate.boneMatrix[20] = 5.0f; int vtype = GE_VTYPE_POS_8BIT | GE_VTYPE_NRM_8BIT | GE_VTYPE_WEIGHT_8BIT | (1 << GE_VTYPE_WEIGHTCOUNT_SHIFT); + u32 vertTypeID = GetVertTypeID(vtype, 0, true); // enable skinning in decode dec.Add8(128 + 64, 128 - 64); dec.Add8(127, 0, 128); dec.Add8(127, 0, 128); for (int jit = 0; jit <= 1; ++jit) { - dec.Execute(vtype, 0, jit == 1); + dec.Execute(vertTypeID, 0, jit == 1); dec.AssertFloat("TestVertex8Skin-Nrm", (2.0f * 1.5f + 1.0f * 0.5f) * 127.0f / 128.0f, 0.0f, 2.0f * 5.0f * -1.0f); dec.AssertFloat("TestVertex8Skin-Pos", (2.0f * 1.5f + 1.0f * 0.5f) * 127.0f / 128.0f, 0.0f, 2.0f * 5.0f * -1.0f); } @@ -575,7 +575,6 @@ static bool TestVertex8Skin() { static bool TestVertex16Skin() { VertexDecoderTestHarness dec; VertexDecoderOptions opts{}; - opts.applySkinInDecode = true; dec.SetOptions(opts); for (int i = 0; i < 8 * 12; ++i) { @@ -590,13 +589,14 @@ static bool TestVertex16Skin() { gstate.boneMatrix[20] = 5.0f; int vtype = GE_VTYPE_POS_16BIT | GE_VTYPE_NRM_16BIT | GE_VTYPE_WEIGHT_16BIT | (1 << GE_VTYPE_WEIGHTCOUNT_SHIFT); + u32 vertTypeID = GetVertTypeID(vtype, 0, true); // enable skinning in decode dec.Add16(32768 + 16384, 32768 - 16384); dec.Add16(32767, 0, 32768); dec.Add16(32767, 0, 32768); for (int jit = 0; jit <= 1; ++jit) { - dec.Execute(vtype, 0, jit == 1); + dec.Execute(vertTypeID, 0, jit == 1); dec.AssertFloat("TestVertex16Skin-Nrm", (2.0f * 1.5f + 1.0f * 0.5f) * 32767.0f / 32768.0f, 0.0f, 2.0f * 5.0f * -1.0f); dec.AssertFloat("TestVertex16Skin-Pos", (2.0f * 1.5f + 1.0f * 0.5f) * 32767.0f / 32768.0f, 0.0f, 2.0f * 5.0f * -1.0f); } @@ -607,7 +607,6 @@ static bool TestVertex16Skin() { static bool TestVertexFloatSkin() { VertexDecoderTestHarness dec; VertexDecoderOptions opts{}; - opts.applySkinInDecode = true; dec.SetOptions(opts); for (int i = 0; i < 8 * 12; ++i) { @@ -622,13 +621,14 @@ static bool TestVertexFloatSkin() { gstate.boneMatrix[20] = 5.0f; int vtype = GE_VTYPE_POS_FLOAT | GE_VTYPE_NRM_FLOAT | GE_VTYPE_WEIGHT_FLOAT | (1 << GE_VTYPE_WEIGHTCOUNT_SHIFT); + u32 vertTypeID = GetVertTypeID(vtype, 0, true); // enable skinning in decode dec.AddFloat(1.5f, 0.5f); dec.AddFloat(1.0f, 0, -1.0f); dec.AddFloat(1.0f, 0, -1.0f); for (int jit = 0; jit <= 1; ++jit) { - dec.Execute(vtype, 0, jit == 1); + dec.Execute(vertTypeID, 0, jit == 1); dec.AssertFloat("TestVertexFloatSkin-Nrm", (2.0f * 1.5f + 1.0f * 0.5f) * 1.0f, 0.0f, 2.0f * 5.0f * -1.0f); dec.AssertFloat("TestVertexFloatSkin-Pos", (2.0f * 1.5f + 1.0f * 0.5f) * 1.0f, 0.0f, 2.0f * 5.0f * -1.0f); }