From 337946db2546074202269de39ff3087f91e05746 Mon Sep 17 00:00:00 2001 From: patrickvl Date: Sat, 24 Oct 2020 12:26:27 +0200 Subject: [PATCH 1/4] Simplfy pixel shader constant handling; Since we've ported over to Direct3D 9, and we're using pixel shader version 1.4, we've got more than enough constants available to remove the need for constant packing. Also, there was a left-over patch on SetPixelShaderConstant which must no longer be applied, since nowadays we read constant values straight from their corresponding render state slots. This also implies we no longer need to declare the final combiner constants as part of the shader assembly, because these 2 are also read from their corresponding xbox render state slots, and thus can be transferred to host on each update. This will likely improve the output of pixel shaders which stay otherwise unchanged but rely on changing constant values. --- import/subhook | 2 +- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 40 ------ .../Direct3D9/Direct3D9.cpp.unused-patches | 40 ++++++ src/core/hle/D3D8/Direct3D9/Direct3D9.h | 15 -- src/core/hle/D3D8/XbPixelShader.cpp | 128 +++--------------- src/core/hle/Patches.cpp | 2 +- 6 files changed, 60 insertions(+), 167 deletions(-) diff --git a/import/subhook b/import/subhook index 29cb47ea7..5073ab41a 160000 --- a/import/subhook +++ b/import/subhook @@ -1 +1 @@ -Subproject commit 29cb47ea7674b36cf2b742c11cf2568add1f47fc +Subproject commit 5073ab41a88a07eba42877d9285601d319b14067 diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 037fcb9dc..d8f7b31db 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -8780,43 +8780,3 @@ xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_GetMaterial) hRet = D3D_OK; } } - -// LTCG specific D3DDevice_SetPixelShaderConstant function... -// This uses a custom calling convention where parameter is passed in ECX, EAX -// TODO: Log function is not working due lost parameter in EAX. -// Test-case: Otogi 2, Ninja Gaiden: Black -xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_SetPixelShaderConstant_4) -( - CONST PVOID pConstantData -) -{ - DWORD Register; - DWORD ConstantCount; - - __asm { - mov Register, ecx - mov ConstantCount, eax - } - - //LOG_FUNC_BEGIN - // LOG_FUNC_ARG(Register) - // LOG_FUNC_ARG(pConstantData) - // LOG_FUNC_ARG(ConstantCount) - // LOG_FUNC_END; - EmuLog(LOG_LEVEL::DEBUG, "D3DDevice_SetPixelShaderConstant_4(Register : %d pConstantData : %08X ConstantCount : %d);", Register, pConstantData, ConstantCount); - - HRESULT hRet = g_pD3DDevice->SetPixelShaderConstantF - ( - Register, - (PixelShaderConstantType*)pConstantData, - ConstantCount - ); - //DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetPixelShaderConstant"); - - if(FAILED(hRet)) - { - EmuLog(LOG_LEVEL::WARNING, "We're lying about setting a pixel shader constant!"); - - hRet = D3D_OK; - } -} diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp.unused-patches b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp.unused-patches index 2f72e5d08..3a3e658b6 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp.unused-patches +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp.unused-patches @@ -4155,3 +4155,43 @@ xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_GetTransform) HRESULT hRet = g_pD3DDevice->GetTransform(State, pMatrix); DEBUG_D3DRESULT(hRet, "g_pD3DDevice->GetTransform"); } + +// LTCG specific D3DDevice_SetPixelShaderConstant function... +// This uses a custom calling convention where parameter is passed in ECX, EAX +// TODO: Log function is not working due lost parameter in EAX. +// Test-case: Otogi 2, Ninja Gaiden: Black +xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_SetPixelShaderConstant_4) +( + CONST PVOID pConstantData +) +{ + DWORD Register; + DWORD ConstantCount; + + __asm { + mov Register, ecx + mov ConstantCount, eax + } + + //LOG_FUNC_BEGIN + // LOG_FUNC_ARG(Register) + // LOG_FUNC_ARG(pConstantData) + // LOG_FUNC_ARG(ConstantCount) + // LOG_FUNC_END; + EmuLog(LOG_LEVEL::DEBUG, "D3DDevice_SetPixelShaderConstant_4(Register : %d pConstantData : %08X ConstantCount : %d);", Register, pConstantData, ConstantCount); + + HRESULT hRet = g_pD3DDevice->SetPixelShaderConstantF + ( + Register, + (PixelShaderConstantType*)pConstantData, + ConstantCount + ); + //DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetPixelShaderConstant"); + + if(FAILED(hRet)) + { + EmuLog(LOG_LEVEL::WARNING, "We're lying about setting a pixel shader constant!"); + + hRet = D3D_OK; + } +} diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.h b/src/core/hle/D3D8/Direct3D9/Direct3D9.h index 6e7842c08..e4756fff8 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.h +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.h @@ -419,21 +419,6 @@ xbox::hresult_xt WINAPI EMUPATCH(D3DDevice_CreateVertexShader) dword_xt Usage ); -// ****************************************************************** -// * patch: D3DDevice_SetPixelShaderConstant -// ****************************************************************** -xbox::void_xt WINAPI EMUPATCH(D3DDevice_SetPixelShaderConstant) -( - dword_xt Register, - CONST PVOID pConstantData, - dword_xt ConstantCount -); - -xbox::void_xt WINAPI EMUPATCH(D3DDevice_SetPixelShaderConstant_4) -( - CONST PVOID pConstantData -); - // ****************************************************************** // * patch: D3DDevice_SetVertexShaderConstant // ****************************************************************** diff --git a/src/core/hle/D3D8/XbPixelShader.cpp b/src/core/hle/D3D8/XbPixelShader.cpp index 955a2a9bf..cb73518eb 100644 --- a/src/core/hle/D3D8/XbPixelShader.cpp +++ b/src/core/hle/D3D8/XbPixelShader.cpp @@ -792,8 +792,6 @@ typedef struct _PSH_RECOMPILED_SHADER { xbox::X_D3DPIXELSHADERDEF PSDef; std::string NewShaderStr; DWORD ConvertedHandle; - bool ConstInUse[PSH_XBOX_CONSTANT_MAX]; - int ConstMapping[PSH_XBOX_CONSTANT_MAX]; } PSH_RECOMPILED_SHADER, *PPSH_RECOMPILED_SHADER; @@ -907,8 +905,6 @@ struct PSH_XBOX_SHADER { void ConvertXboxOpcodesToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef); void _SetColor(/*var OUT*/PSH_INTERMEDIATE_FORMAT &NewIns, D3DCOLOR ConstColor); void _SetColor(/*var OUT*/PSH_INTERMEDIATE_FORMAT &NewIns, D3DCOLORVALUE ConstColor); - int _MapConstant(int ConstNr, bool *NativeConstInUse); - int _HandleConst(int XboxConst, /*var OUT*/PSH_RECOMPILED_SHADER *Recompiled, bool *NativeConstInUse, bool *EmittedNewConstant); bool ConvertConstantsToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef, /*var OUT*/PSH_RECOMPILED_SHADER *Recompiled); bool RemoveUselessWrites(); int MaxRegisterCount(PSH_ARGUMENT_TYPE aRegType); @@ -1266,8 +1262,8 @@ bool PSH_IMD_ARGUMENT::SetScaleConstRegister(float factor, const PSH_RECOMPILED_ DWORD mask = Mask; int address = Address; - const int mappedConstant0 = pRecompiled.ConstMapping[PSH_XBOX_CONSTANT_MUL0]; - const int mappedConstant1 = pRecompiled.ConstMapping[PSH_XBOX_CONSTANT_MUL1]; + const int mappedConstant0 = PSH_XBOX_CONSTANT_MUL0; + const int mappedConstant1 = PSH_XBOX_CONSTANT_MUL1; if (factor < 0.0f) { @@ -1351,8 +1347,8 @@ bool PSH_IMD_ARGUMENT::SetScaleBemLumRegister(D3DTEXTURESTAGESTATETYPE factor, i DWORD mask = Mask; int address = Address; - const int mappedConstant0 = pRecompiled.ConstMapping[PSH_XBOX_CONSTANT_BEM + stage]; - const int mappedConstant1 = pRecompiled.ConstMapping[PSH_XBOX_CONSTANT_LUM + stage]; + const int mappedConstant0 = PSH_XBOX_CONSTANT_BEM + stage; + const int mappedConstant1 = PSH_XBOX_CONSTANT_LUM + stage; switch (factor) { @@ -3396,8 +3392,6 @@ bool PSH_XBOX_SHADER::MoveRemovableParametersRight() return Result; } // MoveRemovableParametersRight -//bool PSH_XBOX_SHADER::ConvertConstantsToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef, /*var OUT*/PSH_RECOMPILED_SHADER *Recompiled) - void PSH_XBOX_SHADER::_SetColor(/*var OUT*/PSH_INTERMEDIATE_FORMAT &NewIns, D3DCOLOR ConstColor) { D3DXCOLOR XColor; @@ -3420,90 +3414,27 @@ bool PSH_XBOX_SHADER::MoveRemovableParametersRight() NewIns.Parameters[3].SetConstValue(ConstColor.a); } - // Try to fixup constants above the limit (c7 for PS.1.3) : - int PSH_XBOX_SHADER::_MapConstant(int ConstNr, bool *NativeConstInUse) - { - // 1-to-1 mapping for constants that can be supported native (if not used already) : - if ((ConstNr < MaxConstantFloatRegisters) && (!NativeConstInUse[ConstNr])) - { - return ConstNr; - } - - // Assign not-yet-defined constants bottom-to-up : - int Result = 0; - while (Result < MaxConstantFloatRegisters) - { - if (!NativeConstInUse[Result]) - return Result; - - ++Result; - } - - // Unresolved - fallback to 1st constant : - if (Result >= MaxConstantFloatRegisters) - Result = 0; - - EmuLog(LOG_LEVEL::WARNING, "; Too many constants to emulate, this pixel shader will give unexpected output!"); - return Result; - } - - int PSH_XBOX_SHADER::_HandleConst(int XboxConst, /*var OUT*/PSH_RECOMPILED_SHADER *Recompiled, bool *NativeConstInUse, bool *EmittedNewConstant) - { - int NativeConst; - - if (!Recompiled->ConstInUse[XboxConst]) - { - // Determine and remember a new mapping to native : - NativeConst = _MapConstant(XboxConst, NativeConstInUse); - NativeConstInUse[NativeConst] = true; - Recompiled->ConstMapping[XboxConst] = NativeConst; - Recompiled->ConstInUse[XboxConst] = true; - // Make sure we can check this is a new constant (so we can emit a constant declaration - // for any final combiner constants - because those cannot be set via SetPixelShaderConstant) : - *EmittedNewConstant = true; - } - - // Return the (previously) determined mapping : - return Recompiled->ConstMapping[XboxConst]; - } - bool PSH_XBOX_SHADER::ConvertConstantsToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef, /*var OUT*/PSH_RECOMPILED_SHADER *Recompiled) { int i, j; PPSH_INTERMEDIATE_FORMAT Cur; PPSH_IMD_ARGUMENT CurArg; - bool NativeConstInUse[224]; // Note : 224 = highest possible MaxConstantFloatRegisters int16_t OriginalConstantNr; - bool EmittedNewConstant = false; PSH_INTERMEDIATE_FORMAT NewIns = {}; - bool Result = false; - - // Note : Recompiled.ConstMapping and Recompiled.ConstInUse[i] are still empty here. - for (i = 0; i < MaxConstantFloatRegisters; i++) - NativeConstInUse[i] = false; - - Result = true; - NewIns.Initialize(PO_DEF); // Add constants used to represent common powers of 2 used by instruction and argument modifiers // Represent constant 0.0 and common powers of 2 divisions - NewIns.Output[0].SetRegister(PARAM_C, _HandleConst(PSH_XBOX_CONSTANT_MUL1, Recompiled, &NativeConstInUse[0], &EmittedNewConstant), MASK_RGBA); + NewIns.Output[0].SetRegister(PARAM_C, PSH_XBOX_CONSTANT_MUL1, MASK_RGBA); _SetColor(NewIns, { 0.0, 1.0 / 2.0, 1.0 / 4.0, 1.0 / 8.0 }); InsertIntermediate(&NewIns, 1); // Represent common powers of 2 constants, also used as multipliers - NewIns.Output[0].SetRegister(PARAM_C, _HandleConst(PSH_XBOX_CONSTANT_MUL0, Recompiled, &NativeConstInUse[0], &EmittedNewConstant), MASK_RGBA); + NewIns.Output[0].SetRegister(PARAM_C, PSH_XBOX_CONSTANT_MUL0, MASK_RGBA); _SetColor(NewIns, {1.0, 2.0, 4.0, 8.0}); InsertIntermediate(&NewIns, 1); - for (i = 0; i < xbox::X_D3DTS_STAGECOUNT; i++) - { - _HandleConst(PSH_XBOX_CONSTANT_BEM + i, Recompiled, &NativeConstInUse[0], &EmittedNewConstant); - _HandleConst(PSH_XBOX_CONSTANT_LUM + i, Recompiled, &NativeConstInUse[0], &EmittedNewConstant); - } - // Loop over all opcodes to update the constant-indexes (Xbox uses C0 and C1 in each combiner) : for (i = 0; i < IntermediateCount; i++) { @@ -3521,7 +3452,7 @@ bool PSH_XBOX_SHADER::ConvertConstantsToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef if (CurArg->Mask != MASK_A) { CurArg->Type = PARAM_C; - CurArg->Address = _HandleConst(PSH_XBOX_CONSTANT_FOG, Recompiled, &NativeConstInUse[0], &EmittedNewConstant); + CurArg->Address = PSH_XBOX_CONSTANT_FOG; CurArg->Mask = CurArg->Mask & (!MASK_A); } else @@ -3541,7 +3472,6 @@ bool PSH_XBOX_SHADER::ConvertConstantsToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef // Make sure we can detect new constants (and if it was C0 or C1), // as we need this for fixing up final combiner constants : - EmittedNewConstant = false; OriginalConstantNr = CurArg->Address; // For each constant being addressed, we find out which Xbox constant it is, @@ -3551,16 +3481,16 @@ bool PSH_XBOX_SHADER::ConvertConstantsToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef { // The final combiner has a separate C0 constant : if (Cur->CombinerStageNr == XFC_COMBINERSTAGENR) - CurArg->Address = _HandleConst(PSH_XBOX_CONSTANT_FC0, Recompiled, &NativeConstInUse[0], &EmittedNewConstant); + CurArg->Address = PSH_XBOX_CONSTANT_FC0; else { // See if C0 has a unique index per combiner stage : if (CombinerHasUniqueC0) // C0 actually ranges from c0 to c7, one for each possible combiner stage (X_D3DRS_PSCONSTANT0_0..X_D3DRS_PSCONSTANT0_7) : - CurArg->Address = _HandleConst(Cur->CombinerStageNr, Recompiled, &NativeConstInUse[0], &EmittedNewConstant); + CurArg->Address = Cur->CombinerStageNr; else // Non-unique just reads the same C0 in every stage : - CurArg->Address = _HandleConst(0, Recompiled, &NativeConstInUse[0], &EmittedNewConstant); + CurArg->Address = 0; } break; } @@ -3569,43 +3499,24 @@ bool PSH_XBOX_SHADER::ConvertConstantsToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef { // The final combiner has a separate C1 constant : if (Cur->CombinerStageNr == XFC_COMBINERSTAGENR) - CurArg->Address = _HandleConst(PSH_XBOX_CONSTANT_FC1, Recompiled, &NativeConstInUse[0], &EmittedNewConstant); + CurArg->Address = PSH_XBOX_CONSTANT_FC1; else { // See if C1 has a unique index per combiner stage : if (CombinerHasUniqueC1) // C1 actually ranges from c8 to c15, one for each possible combiner stage (X_D3DRS_PSCONSTANT1_0..X_D3DRS_PSCONSTANT1_7) : - CurArg->Address = _HandleConst(Cur->CombinerStageNr + 8, Recompiled, &NativeConstInUse[0], &EmittedNewConstant); + CurArg->Address = Cur->CombinerStageNr + 8; else // Non-unique just reads the same C1 in every stage : - CurArg->Address = _HandleConst(1, Recompiled, &NativeConstInUse[0], &EmittedNewConstant); + CurArg->Address = 1; } break; } } // switch - - // New constants solely used for the final combiner must be DEFined separately, - // as there's no other way to set these (SetPixelShaderConstant can only write - // to the 16 slots X_D3DRS_PSCONSTANT1_0..X_D3DRS_PSCONSTANT1_7) : - if ((Cur->CombinerStageNr == XFC_COMBINERSTAGENR) && EmittedNewConstant) - { - // Output a new opcode to define this constant : - NewIns.Initialize(PO_DEF); - NewIns.Output[0].SetRegister(PARAM_C, CurArg->Address, MASK_RGBA); - if (OriginalConstantNr == 0) - _SetColor(NewIns, pPSDef->PSFinalCombinerConstant0); - else - _SetColor(NewIns, pPSDef->PSFinalCombinerConstant1); - - // PO_DEF opcodes go after the initial PO_XPS (which is not yet replaced by PO_COMMENT+PO_PS, - // see ConvertXboxOpcodesToNative calling ConvertXPSToNative for that) - InsertIntermediate(&NewIns, 1); - Result = true; - } } // for arguments } // for opcodes - return Result; + return true; } // ConvertConstantsToNative bool PSH_XBOX_SHADER::RemoveUselessWrites() @@ -5234,9 +5145,7 @@ bool PSH_XBOX_SHADER::FixupPixelShader() // TODO : Fixup the usage of non-existent register numbers (like FakeRegNr_Sum and FakeRegNr_Prod) // TODO : Fixup the usage of the unsupported INSMOD_BIAS and INSMOD_BX2 instruction modifiers // TODO : Use the INSMOD_SAT instruction modifier instead of the ARGMOD_SATURATE argument modifier - // TODO : Condense constants registers, to avoid the non-existant C8-C15 (requires a mapping in SetPixelShaderConstant too...) // TODO : Convert numeric arguments (-2, -1, 0, 1, 2) into modifiers on the other argument - // TODO : Complete to port to D3D9 to support all 18 constants (including C8..C15 + FC0+FC1) if (CombineInstructions()) Result = true; @@ -6051,7 +5960,7 @@ void DxbxUpdateActivePixelShader() // NOPATCH // as these could have been updated via SetRenderState or otherwise : for (i = 0; i < PSH_XBOX_CONSTANT_MAX; i++) { - if (RecompiledPixelShader->ConstInUse[i]) + // Asume all constants are in use (this is much easier than tracking them for no other purpose than to skip a few here) { // Read the color from the corresponding render state slot : switch (i) { @@ -6068,6 +5977,7 @@ void DxbxUpdateActivePixelShader() // NOPATCH break; case PSH_XBOX_CONSTANT_MUL0: case PSH_XBOX_CONSTANT_MUL1: + // These have already been DEFined at the start of ConvertConstantsToNative continue; case PSH_XBOX_CONSTANT_BEM + 0: case PSH_XBOX_CONSTANT_BEM + 1: @@ -6097,20 +6007,18 @@ void DxbxUpdateActivePixelShader() // NOPATCH value[3] = 0; break; } - default: + default: // Actual constants C0..C15 are stored as-is in (and should thus be read from) the Xbox render state pixel shader constant slots fColor = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSCONSTANT0_0 + i); break; } // Convert it back to 4 floats : //fColor = dwColor; - // Read the register we can use on PC : - Register_ = RecompiledPixelShader->ConstMapping[i]; // TODO : Avoid the following setter if it's no different from the previous update (this might speed things up) // Set the value locally in this register : g_pD3DDevice->SetPixelShaderConstantF ( - Register_, + i, (PixelShaderConstantType*)(&fColor), 1 ); diff --git a/src/core/hle/Patches.cpp b/src/core/hle/Patches.cpp index cc9634814..cd341b0fc 100644 --- a/src/core/hle/Patches.cpp +++ b/src/core/hle/Patches.cpp @@ -133,7 +133,7 @@ std::map g_PatchTable = { PATCH_ENTRY("D3DDevice_SetPalette", xbox::EMUPATCH(D3DDevice_SetPalette), PATCH_HLE_D3D), PATCH_ENTRY("D3DDevice_SetPalette_4", xbox::EMUPATCH(D3DDevice_SetPalette_4), PATCH_HLE_D3D), PATCH_ENTRY("D3DDevice_SetPixelShader", xbox::EMUPATCH(D3DDevice_SetPixelShader), PATCH_HLE_D3D), - PATCH_ENTRY("D3DDevice_SetPixelShaderConstant_4", xbox::EMUPATCH(D3DDevice_SetPixelShaderConstant_4), PATCH_HLE_D3D), + //PATCH_ENTRY("D3DDevice_SetPixelShaderConstant_4", xbox::EMUPATCH(D3DDevice_SetPixelShaderConstant_4), PATCH_HLE_D3D), PATCH_ENTRY("D3DDevice_SetPixelShader_0", xbox::EMUPATCH(D3DDevice_SetPixelShader_0), PATCH_HLE_D3D), PATCH_ENTRY("D3DDevice_SetRenderState_Simple", xbox::EMUPATCH(D3DDevice_SetRenderState_Simple), PATCH_HLE_D3D), PATCH_ENTRY("D3DDevice_SetRenderTarget", xbox::EMUPATCH(D3DDevice_SetRenderTarget), PATCH_HLE_D3D), From eae97f3f0754f6d200064db895eba0765bca75a5 Mon Sep 17 00:00:00 2001 From: patrickvl Date: Sat, 24 Oct 2020 14:06:10 +0200 Subject: [PATCH 2/4] Optimize setting host pixel shader constants, by collecting all values and set them using a single call. Also remove one more unused variable --- src/core/hle/D3D8/XbPixelShader.cpp | 35 +++++++++-------------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/src/core/hle/D3D8/XbPixelShader.cpp b/src/core/hle/D3D8/XbPixelShader.cpp index cb73518eb..52ed02048 100644 --- a/src/core/hle/D3D8/XbPixelShader.cpp +++ b/src/core/hle/D3D8/XbPixelShader.cpp @@ -3419,7 +3419,6 @@ bool PSH_XBOX_SHADER::ConvertConstantsToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef int i, j; PPSH_INTERMEDIATE_FORMAT Cur; PPSH_IMD_ARGUMENT CurArg; - int16_t OriginalConstantNr; PSH_INTERMEDIATE_FORMAT NewIns = {}; NewIns.Initialize(PO_DEF); @@ -3470,10 +3469,6 @@ bool PSH_XBOX_SHADER::ConvertConstantsToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef if (CurArg->Type != PARAM_C) continue; - // Make sure we can detect new constants (and if it was C0 or C1), - // as we need this for fixing up final combiner constants : - OriginalConstantNr = CurArg->Address; - // For each constant being addressed, we find out which Xbox constant it is, // and map it to a native constant (as far as we have space for them) : switch (CurArg->Address) { @@ -5876,7 +5871,7 @@ void DxbxUpdateActivePixelShader() // NOPATCH int i; DWORD Register_; D3DCOLOR dwColor; - D3DXCOLOR fColor; + D3DXCOLOR fColor[PSH_XBOX_CONSTANT_MAX]; HRESULT Result = D3D_OK; @@ -5960,20 +5955,20 @@ void DxbxUpdateActivePixelShader() // NOPATCH // as these could have been updated via SetRenderState or otherwise : for (i = 0; i < PSH_XBOX_CONSTANT_MAX; i++) { - // Asume all constants are in use (this is much easier than tracking them for no other purpose than to skip a few here) + // Assume all constants are in use (this is much easier than tracking them for no other purpose than to skip a few here) { // Read the color from the corresponding render state slot : switch (i) { case PSH_XBOX_CONSTANT_FOG: // Note : FOG.RGB is correct like this, but FOG.a should be coming // from the vertex shader (oFog) - however, D3D8 does not forward this... - fColor = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_FOGCOLOR); + fColor[i] = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_FOGCOLOR); break; case PSH_XBOX_CONSTANT_FC0: - fColor = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSFINALCOMBINERCONSTANT0); + fColor[i] = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSFINALCOMBINERCONSTANT0); break; case PSH_XBOX_CONSTANT_FC1: - fColor = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSFINALCOMBINERCONSTANT1); + fColor[i] = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSFINALCOMBINERCONSTANT1); break; case PSH_XBOX_CONSTANT_MUL0: case PSH_XBOX_CONSTANT_MUL1: @@ -5985,7 +5980,7 @@ void DxbxUpdateActivePixelShader() // NOPATCH case PSH_XBOX_CONSTANT_BEM + 3: { int stage = i - PSH_XBOX_CONSTANT_BEM; - DWORD* value = (DWORD*)&fColor; + DWORD* value = (DWORD*)&fColor[i]; g_pD3DDevice->GetTextureStageState(stage, D3DTSS_BUMPENVMAT00, &value[0]); g_pD3DDevice->GetTextureStageState(stage, D3DTSS_BUMPENVMAT01, &value[1]); @@ -5999,7 +5994,7 @@ void DxbxUpdateActivePixelShader() // NOPATCH case PSH_XBOX_CONSTANT_LUM + 3: { int stage = i - PSH_XBOX_CONSTANT_LUM; - DWORD* value = (DWORD*)&fColor; + DWORD* value = (DWORD*)&fColor[i]; g_pD3DDevice->GetTextureStageState(stage, D3DTSS_BUMPENVLSCALE, &value[0]); g_pD3DDevice->GetTextureStageState(stage, D3DTSS_BUMPENVLOFFSET, &value[1]); @@ -6008,21 +6003,13 @@ void DxbxUpdateActivePixelShader() // NOPATCH break; } default: // Actual constants C0..C15 are stored as-is in (and should thus be read from) the Xbox render state pixel shader constant slots - fColor = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSCONSTANT0_0 + i); + fColor[i] = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSCONSTANT0_0 + i); break; } - - // Convert it back to 4 floats : - //fColor = dwColor; - // TODO : Avoid the following setter if it's no different from the previous update (this might speed things up) - // Set the value locally in this register : - g_pD3DDevice->SetPixelShaderConstantF - ( - i, - (PixelShaderConstantType*)(&fColor), - 1 - ); } + + // Set all host constant values using a single call: + g_pD3DDevice->SetPixelShaderConstantF(0, (PixelShaderConstantType*)(&fColor[0]), PSH_XBOX_CONSTANT_MAX); } } else From c09a90e4591b44defd6af327b88ad0562488893e Mon Sep 17 00:00:00 2001 From: patrickvl Date: Sat, 24 Oct 2020 18:50:33 +0200 Subject: [PATCH 3/4] Remap host pixel shader constant indexes, so that all constants can be set using just one call to SetPixelShaderConstantsF Also, added more notes and code on the PSDef.PSTextureMode field (which lies outside of the render state pixel shader range), and skip the values of the final combiner constants when checking for uniqueness of pixel shader definitions. --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 4 + src/core/hle/D3D8/XbD3D8Types.h | 2 +- src/core/hle/D3D8/XbPixelShader.cpp | 146 ++++++++++++---------- 3 files changed, 87 insertions(+), 65 deletions(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index d8f7b31db..2b39e843c 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -7310,7 +7310,11 @@ xbox::void_xt __declspec(noinline) D3DDevice_SetPixelShaderCommon(xbox::dword_xt // This mirrors the fact that unpatched SetPixelShader does the same thing! // This shouldn't be necessary anymore, but shaders still break if we don't do this if (g_pXbox_PixelShader != nullptr) { + // TODO : If D3DDevice_SetPixelShader() in XDKs don't overwrite the X_D3DRS_PS_RESERVED slot with PSDef.PSTextureModes, + // store it here and restore after memcpy, or alternatively, perform two separate memcpy's (the halves before, and after the reserved slot). memcpy(XboxRenderStates.GetPixelShaderRenderStatePointer(), g_pXbox_PixelShader->pPSDef, sizeof(xbox::X_D3DPIXELSHADERDEF) - 3 * sizeof(DWORD)); + // Copy the PSDef.PSTextureModes field to it's dedicated slot, which lies outside the range of PixelShader render state slots + // Note : This seems to be what XDK's do as well. Needs verification. XboxRenderStates.SetXboxRenderState(xbox::X_D3DRS_PSTEXTUREMODES, g_pXbox_PixelShader->pPSDef->PSTextureModes); } } diff --git a/src/core/hle/D3D8/XbD3D8Types.h b/src/core/hle/D3D8/XbD3D8Types.h index d820763fb..906538f9c 100644 --- a/src/core/hle/D3D8/XbD3D8Types.h +++ b/src/core/hle/D3D8/XbD3D8Types.h @@ -406,7 +406,7 @@ typedef struct _X_D3DPIXELSHADERDEF // <- blueshogun 10/1/07 DWORD PSFinalCombinerConstant1; // X_D3DRS_PSFINALCOMBINERCONSTANT1 : C1 in final combiner DWORD PSRGBOutputs[8]; // X_D3DRS_PSRGBOUTPUTS0..X_D3DRS_PSRGBOUTPUTS7 : Stage 0 RGB outputs DWORD PSCombinerCount; // X_D3DRS_PSCOMBINERCOUNT : Active combiner count (Stages 0-7) - DWORD PSTextureModes; // X_D3DRS_PSTEXTUREMODES: Texture addressing modes + DWORD PSTextureModes; // X_D3DRS_PS_RESERVED (copied from out-of-range X_D3DRS_PSTEXTUREMODES) : Texture addressing modes DWORD PSDotMapping; // X_D3DRS_PSDOTMAPPING : Input mapping for dot product modes DWORD PSInputTexture; // X_D3DRS_PSINPUTTEXTURE : Texture source for some texture modes diff --git a/src/core/hle/D3D8/XbPixelShader.cpp b/src/core/hle/D3D8/XbPixelShader.cpp index 52ed02048..a4d7247a2 100644 --- a/src/core/hle/D3D8/XbPixelShader.cpp +++ b/src/core/hle/D3D8/XbPixelShader.cpp @@ -627,15 +627,24 @@ constexpr int PSH_XBOX_MAX_C_REGISTER_COUNT = 16; constexpr int PSH_XBOX_MAX_R_REGISTER_COUNT = 2; constexpr int PSH_XBOX_MAX_T_REGISTER_COUNT = 4; constexpr int PSH_XBOX_MAX_V_REGISTER_COUNT = 2; -// Extra constants to support features not present in Native D3D : -constexpr int PSH_XBOX_CONSTANT_FOG = PSH_XBOX_MAX_C_REGISTER_COUNT; // = 16 -constexpr int PSH_XBOX_CONSTANT_FC0 = PSH_XBOX_CONSTANT_FOG + 1; // = 17 -constexpr int PSH_XBOX_CONSTANT_FC1 = PSH_XBOX_CONSTANT_FC0 + 1; // = 18 -constexpr int PSH_XBOX_CONSTANT_MUL0 = PSH_XBOX_CONSTANT_FC1 + 1; // = 19 -constexpr int PSH_XBOX_CONSTANT_MUL1 = PSH_XBOX_CONSTANT_MUL0 + 1; // = 20 -constexpr int PSH_XBOX_CONSTANT_BEM = PSH_XBOX_CONSTANT_MUL1 + 1; // = 21 -constexpr int PSH_XBOX_CONSTANT_LUM = PSH_XBOX_CONSTANT_BEM + 4; // = 25 -constexpr int PSH_XBOX_CONSTANT_MAX = PSH_XBOX_CONSTANT_LUM + 4; // = 29 + +// Mapping indices of Xbox register combiner constants to host pixel shader constants; +// The first 16 are identity-mapped (C0_1 .. C0_7 are C0 .. C7 on host, C1_0 .. C1_7 are C8 .. C15 on host) : +constexpr int PSH_XBOX_CONSTANT_C0 = 0; // = 0..15 +// Then two final combiner constants : +constexpr int PSH_XBOX_CONSTANT_FC0 = PSH_XBOX_CONSTANT_C0 + PSH_XBOX_MAX_C_REGISTER_COUNT; // = 16 +constexpr int PSH_XBOX_CONSTANT_FC1 = PSH_XBOX_CONSTANT_FC0 + 1; // = 17 +// Fog requires a constant (as host PS1.4 doesn't support the FOG register) +constexpr int PSH_XBOX_CONSTANT_FOG = PSH_XBOX_CONSTANT_FC1 + 1; // = 18 +// Bump Environment Material registers +constexpr int PSH_XBOX_CONSTANT_BEM = PSH_XBOX_CONSTANT_FOG + 1; // = 19..22 +// Bump map Luminance registers +constexpr int PSH_XBOX_CONSTANT_LUM = PSH_XBOX_CONSTANT_BEM + 4; // = 23..26 +// This concludes the set of constants that need to be set on host : +constexpr int PSH_XBOX_CONSTANT_MAX = PSH_XBOX_CONSTANT_LUM + 4; // = 27 +// After those, we need two constants for literal values, which we DEF'ine in ConvertConstantsToNative : +constexpr int PSH_XBOX_CONSTANT_MUL0 = PSH_XBOX_CONSTANT_MAX; // = 27 +constexpr int PSH_XBOX_CONSTANT_MUL1 = PSH_XBOX_CONSTANT_MUL0 + 1; // = 28 constexpr int FakeRegNr_Sum = PSH_XBOX_MAX_T_REGISTER_COUNT + 0; constexpr int FakeRegNr_Prod = PSH_XBOX_MAX_T_REGISTER_COUNT + 1; @@ -1256,8 +1265,6 @@ bool PSH_IMD_ARGUMENT::HasModifier(PSH_ARG_MODIFIER modifier) bool PSH_IMD_ARGUMENT::SetScaleConstRegister(float factor, const PSH_RECOMPILED_SHADER& pRecompiled) { - bool result = false; - PSH_ARG_MODIFIERs modifiers = 0; DWORD mask = Mask; int address = Address; @@ -1269,81 +1276,71 @@ bool PSH_IMD_ARGUMENT::SetScaleConstRegister(float factor, const PSH_RECOMPILED_ { factor = -factor; modifiers = (1 << ARGMOD_NEGATE); + // This inversion is here to support negative scales, but it's not an actual match yet. } + // Note : 'switch(factor)' can't be used here, since that requires an ordinal value (and factor is a float) if (factor == 1.0f) { address = mappedConstant0; mask = MASK_R; - result = true; } else if (factor == 2.0f) { address = mappedConstant0; mask = MASK_G; - result = true; } else if (factor == 4.0f) { address = mappedConstant0; mask = MASK_B; - result = true; } else if (factor == 8.0f) { address = mappedConstant0; mask = MASK_A; - result = true; } else if (factor == 0.0f) { address = mappedConstant1; mask = MASK_R; - result = true; } else if (factor == 1.0f / 2.0f) { address = mappedConstant1; mask = MASK_G; - result = true; } else if (factor == 1.0f / 4.0f) { address = mappedConstant1; mask = MASK_B; - result = true; } else if (factor == 1.0f / 8.0f) { address = mappedConstant1; mask = MASK_A; - result = true; } + else return false; - if (result) - { - Type = PARAM_C; - Address = address; - Mask = mask; - Modifiers = modifiers; - Multiplier = 1.0f; - } + Type = PARAM_C; + Address = address; + Mask = mask; + Modifiers = modifiers; + Multiplier = 1.0f; - return result; + return true; } bool PSH_IMD_ARGUMENT::SetScaleBemLumRegister(D3DTEXTURESTAGESTATETYPE factor, int stage, const PSH_RECOMPILED_SHADER& pRecompiled) { - bool result = false; - - PSH_ARG_MODIFIERs modifiers = 0; + const PSH_ARG_MODIFIERs modifiers = 0; DWORD mask = Mask; int address = Address; @@ -1356,56 +1353,48 @@ bool PSH_IMD_ARGUMENT::SetScaleBemLumRegister(D3DTEXTURESTAGESTATETYPE factor, i { address = mappedConstant0; mask = MASK_R; - result = true; break; } case D3DTSS_BUMPENVMAT01: { address = mappedConstant0; mask = MASK_G; - result = true; break; } case D3DTSS_BUMPENVMAT11: { address = mappedConstant0; mask = MASK_B; - result = true; break; } case D3DTSS_BUMPENVMAT10: { address = mappedConstant0; mask = MASK_A; - result = true; break; } case D3DTSS_BUMPENVLSCALE: { address = mappedConstant1; mask = MASK_R; - result = true; break; } case D3DTSS_BUMPENVLOFFSET: { address = mappedConstant1; mask = MASK_G; - result = true; break; } + default: return false; } - if (result) - { - Type = PARAM_C; - Address = address; - Mask = mask; - Modifiers = modifiers; - Multiplier = 1.0f; - } + Type = PARAM_C; + Address = address; + Mask = mask; + Modifiers = modifiers; + Multiplier = 1.0f; - return result; + return true; } std::string PSH_IMD_ARGUMENT::ToString() @@ -5862,6 +5851,39 @@ static const std::vector g_RecompiledPixelShaders; +bool ArePSDefsIdentical(xbox::X_D3DPIXELSHADERDEF &PSDef1, xbox::X_D3DPIXELSHADERDEF &PSDef2) +{ + // Only compare the [*]-marked members, which forms the unique shader declaration (ignore the constants and Xbox Direct3D8 run-time fields) : + // [*] DWORD PSAlphaInputs[8]; // X_D3DRS_PSALPHAINPUTS0..X_D3DRS_PSALPHAINPUTS7 : Alpha inputs for each stage + // [*] DWORD PSFinalCombinerInputsABCD; // X_D3DRS_PSFINALCOMBINERINPUTSABCD : Final combiner inputs + // [*] DWORD PSFinalCombinerInputsEFG; // X_D3DRS_PSFINALCOMBINERINPUTSEFG : Final combiner inputs (continued) + if (memcmp(&(PSDef1.PSAlphaInputs[0]), &(PSDef2.PSAlphaInputs[0]), (8 + 1 + 1) * sizeof(DWORD)) != 0) + return false; + + // [-] DWORD PSConstant0[8]; // X_D3DRS_PSCONSTANT0_0..X_D3DRS_PSCONSTANT0_7 : C0 for each stage + // [-] DWORD PSConstant1[8]; // X_D3DRS_PSCONSTANT1_0..X_D3DRS_PSCONSTANT1_7 : C1 for each stage + // [*] DWORD PSAlphaOutputs[8]; // X_D3DRS_PSALPHAOUTPUTS0..X_D3DRS_PSALPHAOUTPUTS7 : Alpha output for each stage + // [*] DWORD PSRGBInputs[8]; // X_D3DRS_PSRGBINPUTS0..X_D3DRS_PSRGBINPUTS7 : RGB inputs for each stage + // [*] DWORD PSCompareMode; // X_D3DRS_PSCOMPAREMODE : Compare modes for clipplane texture mode + if (memcmp(&(PSDef1.PSAlphaOutputs[0]), &(PSDef2.PSAlphaOutputs[0]), (8 + 8 + 1) * sizeof(DWORD)) != 0) + return false; + + // [-] DWORD PSFinalCombinerConstant0; // X_D3DRS_PSFINALCOMBINERCONSTANT0 : C0 in final combiner + // [-] DWORD PSFinalCombinerConstant1; // X_D3DRS_PSFINALCOMBINERCONSTANT1 : C1 in final combiner + // [*] DWORD PSRGBOutputs[8]; // X_D3DRS_PSRGBOUTPUTS0..X_D3DRS_PSRGBOUTPUTS7 : Stage 0 RGB outputs + // [*] DWORD PSCombinerCount; // X_D3DRS_PSCOMBINERCOUNT : Active combiner count (Stages 0-7) + // [*] DWORD PSTextureModes; // X_D3DRS_PS_RESERVED (copied from out-of-range X_D3DRS_PSTEXTUREMODES) : Texture addressing modes + // [*] DWORD PSDotMapping; // X_D3DRS_PSDOTMAPPING : Input mapping for dot product modes + // [*] DWORD PSInputTexture; // X_D3DRS_PSINPUTTEXTURE : Texture source for some texture modes + if (memcmp(&(PSDef1.PSRGBOutputs[0]), &(PSDef2.PSRGBOutputs[0]), (8 + 1 + 1 + 1 + 1) * sizeof(DWORD)) != 0) + return false; + + // [-] DWORD PSC0Mapping; // Mapping of c0 regs to D3D constants + // [-] DWORD PSC1Mapping; // Mapping of c1 regs to D3D constants + // [-] DWORD PSFinalCombinerConstants; // Final combiner constant mapping + return true; +} + void DxbxUpdateActivePixelShader() // NOPATCH { xbox::X_D3DPIXELSHADERDEF *pPSDef; @@ -5869,7 +5891,6 @@ void DxbxUpdateActivePixelShader() // NOPATCH DWORD ConvertedPixelShaderHandle; DWORD CurrentPixelShader; int i; - DWORD Register_; D3DCOLOR dwColor; D3DXCOLOR fColor[PSH_XBOX_CONSTANT_MAX]; @@ -5881,32 +5902,35 @@ void DxbxUpdateActivePixelShader() // NOPATCH // Use the pixel shader stored in D3D__RenderState rather than the set handle // This allows changes made via SetRenderState to actually take effect! - // NOTE: PSTextureModes is in a different location in the X_D3DPIXELSHADERFEF than in Render State mappings + // NOTE: PSTextureModes is in a different location in the X_D3DPIXELSHADERDEF than in Render State mappings // All other fields are the same. // We cast D3D__RenderState to a pPSDef for these fields, but - // manually read from D3D__RenderState[X_D3DRS_PSTEXTUREMODES) for that one field. + // manually read from D3D__RenderState[X_D3DRS_PSTEXTUREMODES] for that one field. // See D3DDevice_SetPixelShaderCommon which implements this pPSDef = g_pXbox_PixelShader != nullptr ? (xbox::X_D3DPIXELSHADERDEF*)(XboxRenderStates.GetPixelShaderRenderStatePointer()) : nullptr; if (pPSDef != nullptr) { + // Create a copy of the pixel shader definition, as it is residing in render state register slots : + xbox::X_D3DPIXELSHADERDEF PSDefCopy = *pPSDef; + // Copy-in the PSTextureModes value which is stored outside the range of Xbox pixel shader render state slots : + PSDefCopy.PSTextureModes = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSTEXTUREMODES); + RecompiledPixelShader = nullptr; // Now, see if we already have a shader compiled for this declaration : + // TODO : Change g_RecompiledPixelShaders into an unordered_map, hash just the identifying PSDef members, and add cache eviction (clearing host resources when pruning) for (auto it = g_RecompiledPixelShaders.begin(); it != g_RecompiledPixelShaders.end(); ++it) { - // Only compare parts that form a unique shader (ignore the constants and Direct3D8 run-time fields) : - if ((memcmp(&(it->PSDef.PSAlphaInputs[0]), &(pPSDef->PSAlphaInputs[0]), (8 + 2) * sizeof(DWORD)) == 0) - && (memcmp(&(it->PSDef.PSAlphaOutputs[0]), &(pPSDef->PSAlphaOutputs[0]), (8 + 8 + 3 + 8 + 4) * sizeof(DWORD)) == 0)) { + if (ArePSDefsIdentical(it->PSDef, PSDefCopy)) { RecompiledPixelShader = &(*it); break; } } - // If none was found, recompile this shader and remember it : if (RecompiledPixelShader == nullptr) { // Recompile this pixel shader : - g_RecompiledPixelShaders.push_back(DxbxRecompilePixelShader(pPSDef)); + g_RecompiledPixelShaders.push_back(DxbxRecompilePixelShader(&PSDefCopy)); RecompiledPixelShader = &g_RecompiledPixelShaders.back(); } @@ -5918,10 +5942,6 @@ void DxbxUpdateActivePixelShader() // NOPATCH if (CurrentPixelShader != ConvertedPixelShaderHandle) g_pD3DDevice->SetPixelShader((IDirect3DPixelShader*)ConvertedPixelShaderHandle); - // Note : We set the constants /after/ setting the shader, so that any - // constants in the shader declaration can be overwritten (this will be - // needed for the final combiner constants at least)! - // TODO: Figure out a method to forward the vertex-shader oFog output to the pixel shader FOG input register : // We could use the unused oT4.x to output fog from the vertex shader, and read it with 'texcoord t4' in pixel shader! // For now, we still disable native fog if pixel shader is said to handle it, this prevents black screen issues in titles using pixel shader fog. @@ -5970,10 +5990,6 @@ void DxbxUpdateActivePixelShader() // NOPATCH case PSH_XBOX_CONSTANT_FC1: fColor[i] = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSFINALCOMBINERCONSTANT1); break; - case PSH_XBOX_CONSTANT_MUL0: - case PSH_XBOX_CONSTANT_MUL1: - // These have already been DEFined at the start of ConvertConstantsToNative - continue; case PSH_XBOX_CONSTANT_BEM + 0: case PSH_XBOX_CONSTANT_BEM + 1: case PSH_XBOX_CONSTANT_BEM + 2: @@ -6002,14 +6018,16 @@ void DxbxUpdateActivePixelShader() // NOPATCH value[3] = 0; break; } - default: // Actual constants C0..C15 are stored as-is in (and should thus be read from) the Xbox render state pixel shader constant slots - fColor[i] = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSCONSTANT0_0 + i); + default: // PSH_XBOX_CONSTANT_C0..C15 are stored as-is in (and should thus be read from) the Xbox render state pixel shader constant slots + fColor[i] = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSCONSTANT0_0 + i - PSH_XBOX_CONSTANT_C0); break; } } // Set all host constant values using a single call: g_pD3DDevice->SetPixelShaderConstantF(0, (PixelShaderConstantType*)(&fColor[0]), PSH_XBOX_CONSTANT_MAX); + // Note PSH_XBOX_CONSTANT_MUL0 and PSH_XBOX_CONSTANT_MUL1 fall outside PSH_XBOX_CONSTANT_MAX + // and have already been 'PO_DEF'ined at the start of ConvertConstantsToNative } } else From b8bb0544024329e60687f071166257c7989fcbb5 Mon Sep 17 00:00:00 2001 From: PatrickvL Date: Mon, 26 Oct 2020 17:27:13 +0100 Subject: [PATCH 4/4] Revert unintentional subhook change --- import/subhook | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/import/subhook b/import/subhook index 5073ab41a..29cb47ea7 160000 --- a/import/subhook +++ b/import/subhook @@ -1 +1 @@ -Subproject commit 5073ab41a88a07eba42877d9285601d319b14067 +Subproject commit 29cb47ea7674b36cf2b742c11cf2568add1f47fc