From 2993546a25380cb2269d6ce536174fbe302f3cbb Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Thu, 5 Jan 2017 08:17:32 +0000 Subject: [PATCH] Remove "Copy" file and old HLE database archive --- src/CxbxKrnl/EmuD3D8/VertexShader - Copy.cpp | 2097 ------------------ src/CxbxKrnl/HLEDataBase/HLE_3911.rar | Bin 30746 -> 0 bytes 2 files changed, 2097 deletions(-) delete mode 100644 src/CxbxKrnl/EmuD3D8/VertexShader - Copy.cpp delete mode 100644 src/CxbxKrnl/HLEDataBase/HLE_3911.rar diff --git a/src/CxbxKrnl/EmuD3D8/VertexShader - Copy.cpp b/src/CxbxKrnl/EmuD3D8/VertexShader - Copy.cpp deleted file mode 100644 index 8bc9ca192..000000000 --- a/src/CxbxKrnl/EmuD3D8/VertexShader - Copy.cpp +++ /dev/null @@ -1,2097 +0,0 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -// ****************************************************************** -// * -// * .,-::::: .,:: .::::::::. .,:: .: -// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;; -// * [[[ '[[,,[[' [[[__[[\. '[[,,[[' -// * $$$ Y$$$P $$""""Y$$ Y$$$P -// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo, -// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm, -// * -// * Cxbx->Win32->CxbxKrnl->EmuD3D8->VertexShader.cpp -// * -// * This file is part of the Cxbx project. -// * -// * Cxbx and Cxbe are free software; you can redistribute them -// * and/or modify them under the terms of the GNU General Public -// * License as published by the Free Software Foundation; either -// * version 2 of the license, or (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have recieved a copy of the GNU General Public License -// * along with this program; see the file COPYING. -// * If not, write to the Free Software Foundation, Inc., -// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. -// * -// * (c) 2002-2004 Aaron Robinson -// * Kingofc -// * -// * All rights reserved -// * -// ****************************************************************** -#define _CXBXKRNL_INTERNAL -#define _XBOXKRNL_DEFEXTRN_ - -#include "CxbxKrnl/CxbxKrnl.h" -#include "CxbxKrnl/Emu.h" -#include "CxbxKrnl/EmuFS.h" -#include "CxbxKrnl/EmuAlloc.h" -#include "CxbxKrnl/EmuXTL.h" - -// **************************************************************************** -// * Vertex shader function recompiler -// **************************************************************************** - -// Local macros -#define VERSION_VS 0xF0 // vs.1.1, not an official value -#define VERSION_XVS 0x20 // Xbox vertex shader -#define VERSION_XVSS 0x73 // Xbox vertex state shader -#define VERSION_XVSW 0x77 // Xbox vertex read/write shader -#define VSH_XBOX_MAX_INSTRUCTION_COUNT 136 // The maximum Xbox shader instruction count -#define VSH_MAX_INTERMEDIATE_COUNT 1024 // The maximum number of intermediate format slots - -// Local types -typedef enum _VSH_FIELD_NAME -{ - FLD_ILU = 0, - FLD_MAC, - FLD_CONST, - FLD_V, - // Input A - FLD_A_NEG, - FLD_A_SWZ_X, - FLD_A_SWZ_Y, - FLD_A_SWZ_Z, - FLD_A_SWZ_W, - FLD_A_R, - FLD_A_MUX, - // Input B - FLD_B_NEG, - FLD_B_SWZ_X, - FLD_B_SWZ_Y, - FLD_B_SWZ_Z, - FLD_B_SWZ_W, - FLD_B_R, - FLD_B_MUX, - // Input C - FLD_C_NEG, - FLD_C_SWZ_X, - FLD_C_SWZ_Y, - FLD_C_SWZ_Z, - FLD_C_SWZ_W, - FLD_C_R_HIGH, - FLD_C_R_LOW, - FLD_C_MUX, - // Output - FLD_OUT_MAC_MASK_X, - FLD_OUT_MAC_MASK_Y, - FLD_OUT_MAC_MASK_Z, - FLD_OUT_MAC_MASK_W, - FLD_OUT_R, - FLD_OUT_ILU_MASK_X, - FLD_OUT_ILU_MASK_Y, - FLD_OUT_ILU_MASK_Z, - FLD_OUT_ILU_MASK_W, - FLD_OUT_O_MASK_X, - FLD_OUT_O_MASK_Y, - FLD_OUT_O_MASK_Z, - FLD_OUT_O_MASK_W, - FLD_OUT_ORB, - FLD_OUT_ADDRESS, - FLD_OUT_MUX, - // Relative addressing - FLD_A0X, - // Final instruction - FLD_FINAL -} -VSH_FIELD_NAME; - -typedef enum _VSH_OREG_NAME -{ - OREG_OPOS, - OREG_UNUSED1, - OREG_UNUSED2, - OREG_OD0, - OREG_OD1, - OREG_OFOG, - OREG_OPTS, - OREG_OB0, - OREG_OB1, - OREG_OT0, - OREG_OT1, - OREG_OT2, - OREG_OT3, - OREG_UNUSED3, - OREG_UNUSED4, - OREG_A0X -} -VSH_OREG_NAME; - -typedef enum _VSH_PARAMETER_TYPE -{ - PARAM_UNKNOWN = 0, - PARAM_R, - PARAM_V, - PARAM_C -} -VSH_PARAMETER_TYPE; - -typedef enum _VSH_OUTPUT_TYPE -{ - OUTPUT_C = 0, - OUTPUT_O -} -VSH_OUTPUT_TYPE; - -typedef enum _VSH_OUTPUT_MUX -{ - OMUX_MAC = 0, - OMUX_ILU -} -VSH_OUTPUT_MUX; - -typedef enum _VSH_ILU -{ - ILU_NOP = 0, - ILU_MOV, - ILU_RCP, - ILU_RCC, - ILU_RSQ, - ILU_EXP, - ILU_LOG, - ILU_LIT -} -VSH_ILU; - -typedef enum _VSH_MAC -{ - MAC_NOP, - MAC_MOV, - MAC_MUL, - MAC_ADD, - MAC_MAD, - MAC_DP3, - MAC_DPH, - MAC_DP4, - MAC_DST, - MAC_MIN, - MAC_MAX, - MAC_SLT, - MAC_SGE, - MAC_ARL -} -VSH_MAC; - -typedef struct _VSH_OPCODE_PARAMS -{ - VSH_ILU ILU; - VSH_MAC MAC; - boolean A; - boolean B; - boolean C; -} -VSH_OPCODE_PARAMS; - -typedef enum _VSH_SWIZZLE -{ - SWIZZLE_X = 0, - SWIZZLE_Y, - SWIZZLE_Z, - SWIZZLE_W -} -VSH_SWIZZLE; - -typedef struct _VSH_PARAMETER -{ - VSH_PARAMETER_TYPE ParameterType; // Parameter type, R, V or C - boolean Neg; // TRUE if negated, FALSE if not - VSH_SWIZZLE Swizzle[4]; // The four swizzles - int16 Address; // Register address -} -VSH_PARAMETER; - -typedef struct _VSH_OUTPUT -{ - // Output register - VSH_OUTPUT_MUX OutputMux; // MAC or ILU used as output - VSH_OUTPUT_TYPE OutputType; // C or O - boolean OutputMask[4]; - int16 OutputAddress; - // MAC output R register - boolean MACRMask[4]; - boolean MACRAddress; - // ILU output R register - boolean ILURMask[4]; - boolean ILURAddress; -} -VSH_OUTPUT; - -// The raw, parsed shader instruction (can be many combined [paired] instructions) -typedef struct _VSH_SHADER_INSTRUCTION -{ - VSH_ILU ILU; - VSH_MAC MAC; - VSH_OUTPUT Output; - VSH_PARAMETER A; - VSH_PARAMETER B; - VSH_PARAMETER C; - boolean a0x; -} -VSH_SHADER_INSTRUCTION; - -typedef enum _VSH_IMD_OUTPUT_TYPE -{ - IMD_OUTPUT_C, - IMD_OUTPUT_R, - IMD_OUTPUT_O, - IMD_OUTPUT_A0X -} -VSH_IMD_OUTPUT_TYPE; - -typedef enum _VSH_IMD_INSTRUCTION_TYPE -{ - IMD_MAC, - IMD_ILU -} -VSH_IMD_INSTRUCTION_TYPE; - -typedef struct _VSH_IMD_OUTPUT -{ - VSH_IMD_OUTPUT_TYPE Type; - boolean Mask[4]; - int16 Address; -} -VSH_IMD_OUTPUT; - -typedef struct _VSH_IMD_PARAMETER -{ - boolean Active; - VSH_PARAMETER Parameter; - boolean IsA0X; -} -VSH_IMD_PARAMETER; - -typedef struct _VSH_INTERMEDIATE_FORMAT -{ - - boolean IsCombined; - VSH_IMD_INSTRUCTION_TYPE InstructionType; - VSH_MAC MAC; - VSH_ILU ILU; - VSH_IMD_OUTPUT Output; - VSH_IMD_PARAMETER Parameters[3]; -} -VSH_INTERMEDIATE_FORMAT; - -// Used for xvu spec definition -typedef struct _VSH_FIELDMAPPING -{ - VSH_FIELD_NAME FieldName; - uint08 SubToken; - uint08 StartBit; - uint08 BitLength; -} -VSH_FIELDMAPPING; - -typedef struct _VSH_XBOX_SHADER -{ - XTL::VSH_SHADER_HEADER ShaderHeader; - uint16 IntermediateCount; - VSH_INTERMEDIATE_FORMAT Intermediate[VSH_MAX_INTERMEDIATE_COUNT]; -} -VSH_XBOX_SHADER; - -// Local constants -static const VSH_FIELDMAPPING g_FieldMapping[] = -{ - // Field Name DWORD BitPos BitSize - { FLD_ILU, 1, 25, 3 }, - { FLD_MAC, 1, 21, 4 }, - { FLD_CONST, 1, 13, 8 }, - { FLD_V, 1, 9, 4 }, - // INPUT A - { FLD_A_NEG, 1, 8, 1 }, - { FLD_A_SWZ_X, 1, 6, 2 }, - { FLD_A_SWZ_Y, 1, 4, 2 }, - { FLD_A_SWZ_Z, 1, 2, 2 }, - { FLD_A_SWZ_W, 1, 0, 2 }, - { FLD_A_R, 2, 28, 4 }, - { FLD_A_MUX, 2, 26, 2 }, - // INPUT B - { FLD_B_NEG, 2, 25, 1 }, - { FLD_B_SWZ_X, 2, 23, 2 }, - { FLD_B_SWZ_Y, 2, 21, 2 }, - { FLD_B_SWZ_Z, 2, 19, 2 }, - { FLD_B_SWZ_W, 2, 17, 2 }, - { FLD_B_R, 2, 13, 4 }, - { FLD_B_MUX, 2, 11, 2 }, - // INPUT C - { FLD_C_NEG, 2, 10, 1 }, - { FLD_C_SWZ_X, 2, 8, 2 }, - { FLD_C_SWZ_Y, 2, 6, 2 }, - { FLD_C_SWZ_Z, 2, 4, 2 }, - { FLD_C_SWZ_W, 2, 2, 2 }, - { FLD_C_R_HIGH, 2, 0, 2 }, - { FLD_C_R_LOW, 3, 30, 2 }, - { FLD_C_MUX, 3, 28, 2 }, - // Output - { FLD_OUT_MAC_MASK_X, 3, 27, 1 }, - { FLD_OUT_MAC_MASK_Y, 3, 26, 1 }, - { FLD_OUT_MAC_MASK_Z, 3, 25, 1 }, - { FLD_OUT_MAC_MASK_W, 3, 24, 1 }, - { FLD_OUT_R, 3, 20, 4 }, - { FLD_OUT_ILU_MASK_X, 3, 19, 1 }, - { FLD_OUT_ILU_MASK_Y, 3, 18, 1 }, - { FLD_OUT_ILU_MASK_Z, 3, 17, 1 }, - { FLD_OUT_ILU_MASK_W, 3, 16, 1 }, - { FLD_OUT_O_MASK_X, 3, 15, 1 }, - { FLD_OUT_O_MASK_Y, 3, 14, 1 }, - { FLD_OUT_O_MASK_Z, 3, 13, 1 }, - { FLD_OUT_O_MASK_W, 3, 12, 1 }, - { FLD_OUT_ORB, 3, 11, 1 }, - { FLD_OUT_ADDRESS, 3, 3, 8 }, - { FLD_OUT_MUX, 3, 2, 1 }, - // Other - { FLD_A0X, 3, 1, 1 }, - { FLD_FINAL, 3, 0, 1 } -}; - -static const VSH_OPCODE_PARAMS g_OpCodeParams[] = -{ - // ILU OP MAC OP ParamA ParamB ParamC - { ILU_MOV, MAC_NOP, FALSE, FALSE, TRUE }, - { ILU_RCP, MAC_NOP, FALSE, FALSE, TRUE }, - { ILU_RCC, MAC_NOP, FALSE, FALSE, TRUE }, - { ILU_RSQ, MAC_NOP, FALSE, FALSE, TRUE }, - { ILU_EXP, MAC_NOP, FALSE, FALSE, TRUE }, - { ILU_LOG, MAC_NOP, FALSE, FALSE, TRUE }, - { ILU_LIT, MAC_NOP, FALSE, FALSE, TRUE }, - { ILU_NOP, MAC_MOV, TRUE, FALSE, FALSE }, - { ILU_NOP, MAC_MUL, TRUE, TRUE, FALSE }, - { ILU_NOP, MAC_ADD, TRUE, FALSE, TRUE }, - { ILU_NOP, MAC_MAD, TRUE, TRUE, TRUE }, - { ILU_NOP, MAC_DP3, TRUE, TRUE, FALSE }, - { ILU_NOP, MAC_DPH, TRUE, TRUE, FALSE }, - { ILU_NOP, MAC_DP4, TRUE, TRUE, FALSE }, - { ILU_NOP, MAC_DST, TRUE, TRUE, FALSE }, - { ILU_NOP, MAC_MIN, TRUE, TRUE, FALSE }, - { ILU_NOP, MAC_MAX, TRUE, TRUE, FALSE }, - { ILU_NOP, MAC_SLT, TRUE, TRUE, FALSE }, - { ILU_NOP, MAC_SGE, TRUE, TRUE, FALSE }, - { ILU_NOP, MAC_ARL, TRUE, FALSE, FALSE } -}; - -static const char* MAC_OpCode[] = -{ - "nop", - "mov", - "mul", - "add", - "mad", - "dp3", - "dph", - "dp4", - "dst", - "min", - "max", - "slt", - "sge", - "mov", // really "arl" - "???", - "???" -}; - -static const char* ILU_OpCode[] = -{ - "nop", - "mov", - "rcp", - "rcc", - "rsq", - "exp", - "log", - "lit" -}; - -static const char* OReg_Name[] = -{ - "oPos", - "???", - "???", - "oD0", - "oD1", - "oFog", - "oPts", - "oB0", - "oB1", - "oT0", - "oT1", - "oT2", - "oT3", - "???", - "???", - "a0.x" -}; - -static inline int IsInUse(const boolean *pMask) -{ - return (pMask[0] || pMask[1] || pMask[2] || pMask[3]); -} - -static inline boolean HasMACR(VSH_SHADER_INSTRUCTION *pInstruction) -{ - return IsInUse(pInstruction->Output.MACRMask) && pInstruction->MAC != MAC_NOP; -} - -static inline boolean HasMACO(VSH_SHADER_INSTRUCTION *pInstruction) -{ - return IsInUse(pInstruction->Output.OutputMask) && - pInstruction->Output.OutputMux == OMUX_MAC && - pInstruction->MAC != MAC_NOP; -} - -static inline boolean HasMACARL(VSH_SHADER_INSTRUCTION *pInstruction) -{ - return /*!IsInUse(pInstruction->Output.OutputMask) && - pInstruction->Output.OutputMux == OMUX_MAC &&*/ - pInstruction->MAC == MAC_ARL; -} - -static inline boolean HasILUR(VSH_SHADER_INSTRUCTION *pInstruction) -{ - return IsInUse(pInstruction->Output.ILURMask) && pInstruction->ILU != ILU_NOP; -} - -static inline boolean HasILUO(VSH_SHADER_INSTRUCTION *pInstruction) -{ - return IsInUse(pInstruction->Output.OutputMask) && - pInstruction->Output.OutputMux == OMUX_ILU && - pInstruction->ILU != ILU_NOP; -} - -// Retrieves a number of bits in the instruction token -static inline int VshGetFromToken(uint32 *pShaderToken, - uint08 SubToken, - uint08 StartBit, - uint08 BitLength) -{ - return (pShaderToken[SubToken] >> StartBit) & ~(0xFFFFFFFF << BitLength); -} - -// Converts the C register address to disassembly format -static inline int16 ConvertCRegister(const int16 CReg) -{ - return ((((CReg >> 5) & 7) - 3) * 32) + (CReg & 31); -} - -uint08 VshGetField(uint32 *pShaderToken, - VSH_FIELD_NAME FieldName) -{ - return (uint08)(VshGetFromToken(pShaderToken, - g_FieldMapping[FieldName].SubToken, - g_FieldMapping[FieldName].StartBit, - g_FieldMapping[FieldName].BitLength)); -} - -static VSH_OPCODE_PARAMS* VshGetOpCodeParams(VSH_ILU ILU, - VSH_MAC MAC) -{ - int i; - - for (i = 0; i < (sizeof(g_OpCodeParams) / sizeof(VSH_OPCODE_PARAMS)); i++) - { - if(ILU != ILU_NOP && ILU == g_OpCodeParams[i].ILU || - MAC != MAC_NOP && MAC == g_OpCodeParams[i].MAC) - { - return (VSH_OPCODE_PARAMS*)&g_OpCodeParams[i]; - } - } - return NULL; -} - -static void VshParseInstruction(uint32 *pShaderToken, - VSH_SHADER_INSTRUCTION *pInstruction) -{ - // First get the instruction(s). - pInstruction->ILU = (VSH_ILU)VshGetField(pShaderToken, FLD_ILU); - pInstruction->MAC = (VSH_MAC)VshGetField(pShaderToken, FLD_MAC); - // Get parameter A - pInstruction->A.ParameterType = (VSH_PARAMETER_TYPE)VshGetField(pShaderToken, FLD_A_MUX); - switch(pInstruction->A.ParameterType) - { - case PARAM_R: - pInstruction->A.Address = VshGetField(pShaderToken, FLD_A_R); - break; - case PARAM_V: - pInstruction->A.Address = VshGetField(pShaderToken, FLD_V); - break; - case PARAM_C: - pInstruction->A.Address = ConvertCRegister(VshGetField(pShaderToken, FLD_CONST)); - break; - default: - EmuWarning("Invalid instruction, parameter A type unknown %d\n", pInstruction->A.ParameterType); - return; - } - pInstruction->A.Neg = VshGetField(pShaderToken, FLD_A_NEG); - pInstruction->A.Swizzle[0] = (VSH_SWIZZLE)VshGetField(pShaderToken, FLD_A_SWZ_X); - pInstruction->A.Swizzle[1] = (VSH_SWIZZLE)VshGetField(pShaderToken, FLD_A_SWZ_Y); - pInstruction->A.Swizzle[2] = (VSH_SWIZZLE)VshGetField(pShaderToken, FLD_A_SWZ_Z); - pInstruction->A.Swizzle[3] = (VSH_SWIZZLE)VshGetField(pShaderToken, FLD_A_SWZ_W); - // Get parameter B - pInstruction->B.ParameterType = (VSH_PARAMETER_TYPE)VshGetField(pShaderToken, FLD_B_MUX); - switch(pInstruction->B.ParameterType) - { - case PARAM_R: - pInstruction->B.Address = VshGetField(pShaderToken, FLD_B_R); - break; - case PARAM_V: - pInstruction->B.Address = VshGetField(pShaderToken, FLD_V); - break; - case PARAM_C: - pInstruction->B.Address = ConvertCRegister(VshGetField(pShaderToken, FLD_CONST)); - break; - default: - DbgVshPrintf("Invalid instruction, parameter B type unknown %d\n", pInstruction->B.ParameterType); - return; - } - pInstruction->B.Neg = VshGetField(pShaderToken, FLD_B_NEG); - pInstruction->B.Swizzle[0] = (VSH_SWIZZLE)VshGetField(pShaderToken, FLD_B_SWZ_X); - pInstruction->B.Swizzle[1] = (VSH_SWIZZLE)VshGetField(pShaderToken, FLD_B_SWZ_Y); - pInstruction->B.Swizzle[2] = (VSH_SWIZZLE)VshGetField(pShaderToken, FLD_B_SWZ_Z); - pInstruction->B.Swizzle[3] = (VSH_SWIZZLE)VshGetField(pShaderToken, FLD_B_SWZ_W); - // Get parameter C - pInstruction->C.ParameterType = (VSH_PARAMETER_TYPE)VshGetField(pShaderToken, FLD_C_MUX); - switch(pInstruction->C.ParameterType) - { - case PARAM_R: - pInstruction->C.Address = VshGetField(pShaderToken, FLD_C_R_HIGH) << 2 | - VshGetField(pShaderToken, FLD_C_R_LOW); - break; - case PARAM_V: - pInstruction->C.Address = VshGetField(pShaderToken, FLD_V); - break; - case PARAM_C: - pInstruction->C.Address = ConvertCRegister(VshGetField(pShaderToken, FLD_CONST)); - break; - default: - DbgVshPrintf("Invalid instruction, parameter C type unknown %d\n", pInstruction->C.ParameterType); - return; - } - pInstruction->C.Neg = VshGetField(pShaderToken, FLD_C_NEG); - pInstruction->C.Swizzle[0] = (VSH_SWIZZLE)VshGetField(pShaderToken, FLD_C_SWZ_X); - pInstruction->C.Swizzle[1] = (VSH_SWIZZLE)VshGetField(pShaderToken, FLD_C_SWZ_Y); - pInstruction->C.Swizzle[2] = (VSH_SWIZZLE)VshGetField(pShaderToken, FLD_C_SWZ_Z); - pInstruction->C.Swizzle[3] = (VSH_SWIZZLE)VshGetField(pShaderToken, FLD_C_SWZ_W); - // Get output - // Output register - pInstruction->Output.OutputType = (VSH_OUTPUT_TYPE)VshGetField(pShaderToken, FLD_OUT_ORB); - switch(pInstruction->Output.OutputType) - { - case OUTPUT_C: - pInstruction->Output.OutputAddress = ConvertCRegister(VshGetField(pShaderToken, FLD_OUT_ADDRESS)); - break; - case OUTPUT_O: - pInstruction->Output.OutputAddress = VshGetField(pShaderToken, FLD_OUT_ADDRESS) & 0xF; - break; - } - pInstruction->Output.OutputMux = (VSH_OUTPUT_MUX)VshGetField(pShaderToken, FLD_OUT_MUX); - pInstruction->Output.OutputMask[0] = VshGetField(pShaderToken, FLD_OUT_O_MASK_X); - pInstruction->Output.OutputMask[1] = VshGetField(pShaderToken, FLD_OUT_O_MASK_Y); - pInstruction->Output.OutputMask[2] = VshGetField(pShaderToken, FLD_OUT_O_MASK_Z); - pInstruction->Output.OutputMask[3] = VshGetField(pShaderToken, FLD_OUT_O_MASK_W); - // MAC output - pInstruction->Output.MACRMask[0] = VshGetField(pShaderToken, FLD_OUT_MAC_MASK_X); - pInstruction->Output.MACRMask[1] = VshGetField(pShaderToken, FLD_OUT_MAC_MASK_Y); - pInstruction->Output.MACRMask[2] = VshGetField(pShaderToken, FLD_OUT_MAC_MASK_Z); - pInstruction->Output.MACRMask[3] = VshGetField(pShaderToken, FLD_OUT_MAC_MASK_W); - pInstruction->Output.MACRAddress = VshGetField(pShaderToken, FLD_OUT_R); - // ILU output - pInstruction->Output.ILURMask[0] = VshGetField(pShaderToken, FLD_OUT_ILU_MASK_X); - pInstruction->Output.ILURMask[1] = VshGetField(pShaderToken, FLD_OUT_ILU_MASK_Y); - pInstruction->Output.ILURMask[2] = VshGetField(pShaderToken, FLD_OUT_ILU_MASK_Z); - pInstruction->Output.ILURMask[3] = VshGetField(pShaderToken, FLD_OUT_ILU_MASK_W); - pInstruction->Output.ILURAddress = VshGetField(pShaderToken, FLD_OUT_R); - // Finally, get a0.x indirect constant addressing - pInstruction->a0x = VshGetField(pShaderToken, FLD_A0X); -} - -// Print functions -static char VshGetRegisterName(VSH_PARAMETER_TYPE ParameterType) -{ - switch(ParameterType) - { - case PARAM_R: - return 'r'; - case PARAM_V: - return 'v'; - case PARAM_C: - return 'c'; - default: - return '?'; - } -} - -static void VshWriteOutputMask(boolean *OutputMask, - char *pDisassembly, - uint32 *pDisassemblyPos) -{ - if(OutputMask[0] && OutputMask[1] && OutputMask[2] && OutputMask[3]) - { - // All compoenents are there, no need to print the mask - return; - } - *pDisassemblyPos += sprintf(pDisassembly + *pDisassemblyPos, ".%s%s%s%s", - OutputMask[0] ? "x" : "", - OutputMask[1] ? "y" : "", - OutputMask[2] ? "z" : "", - OutputMask[3] ? "w" : ""); -} - -static void VshWriteParameter(VSH_IMD_PARAMETER *pParameter, - char *pDisassembly, - uint32 *pDisassemblyPos) -{ - *pDisassemblyPos += sprintf(pDisassembly + *pDisassemblyPos, ", %s%c", - pParameter->Parameter.Neg ? "-" : "", - VshGetRegisterName(pParameter->Parameter.ParameterType)); - if(pParameter->Parameter.ParameterType == PARAM_C && pParameter->IsA0X) - { - // Only display the offset if it's not 0. - if(pParameter->Parameter.Address) - { - *pDisassemblyPos += sprintf(pDisassembly + *pDisassemblyPos, "[a0.x+%d]", pParameter->Parameter.Address); - } - else - { - *pDisassemblyPos += sprintf(pDisassembly + *pDisassemblyPos, "[a0.x]"); - } - } - else - { - *pDisassemblyPos += sprintf(pDisassembly + *pDisassemblyPos, "%d", pParameter->Parameter.Address); - } - // Only bother printing the swizzle if it is not .xyzw - if(!(pParameter->Parameter.Swizzle[0] == 0 && - pParameter->Parameter.Swizzle[1] == 1 && - pParameter->Parameter.Swizzle[2] == 2 && - pParameter->Parameter.Swizzle[3] == 3)) - { - int i; - - *pDisassemblyPos += sprintf(pDisassembly + *pDisassemblyPos, "."); - for (i = 0; i < 4; i++) - { - int j; - char Swizzle = '?'; - switch(pParameter->Parameter.Swizzle[i]) - { - case SWIZZLE_X: - Swizzle = 'x'; - break; - case SWIZZLE_Y: - Swizzle = 'y'; - break; - case SWIZZLE_Z: - Swizzle = 'z'; - break; - case SWIZZLE_W: - Swizzle = 'w'; - break; - } - *pDisassemblyPos += sprintf(pDisassembly + *pDisassemblyPos, "%c", Swizzle); - for (j = i; j < 4; j++) - { - if(pParameter->Parameter.Swizzle[i] != pParameter->Parameter.Swizzle[j]) - { - break; - } - } - if(j == 4) - { - break; - } - } - } -} - -static void VshWriteShader(VSH_XBOX_SHADER *pShader, - char* pDisassembly, - boolean Truncate) -{ - uint32 DisassemblyPos = 0; - switch(pShader->ShaderHeader.Version) - { - case VERSION_VS: - DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "vs.1.1\n"); - break; - case VERSION_XVS: - DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "xvs.1.1\n"); - break; - case VERSION_XVSS: - DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "xvss.1.1\n"); - break; - case VERSION_XVSW: - DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "xvsw.1.1\n"); - break; - default: - break; - } - for (int i = 0; i < pShader->IntermediateCount && (i < 128 || !Truncate); i++) - { - VSH_INTERMEDIATE_FORMAT *pIntermediate = &pShader->Intermediate[i]; - - if(i == 128) - { - DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "; -- Passing the truncation limit --\n"); - } - // Writing combining sign if neccessary - if(pIntermediate->IsCombined) - { - DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "+"); - } - // Print the op code - if(pIntermediate->InstructionType == IMD_MAC) - { - DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "%s ", MAC_OpCode[pIntermediate->MAC]); - } - else - { - DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "%s ", ILU_OpCode[pIntermediate->ILU]); - } - - // Print the output parameter - if(pIntermediate->Output.Type == IMD_OUTPUT_A0X) - { - DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "a0.x"); - } - else - { - switch(pIntermediate->Output.Type) - { - case IMD_OUTPUT_C: - DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "c%d", pIntermediate->Output.Address); - break; - case IMD_OUTPUT_R: - DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "r%d", pIntermediate->Output.Address); - break; - case IMD_OUTPUT_O: - DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "%s", OReg_Name[pIntermediate->Output.Address]); - break; - default: - CxbxKrnlCleanup("Invalid output register in vertex shader!"); - break; - } - VshWriteOutputMask(pIntermediate->Output.Mask, pDisassembly, &DisassemblyPos); - } - // Print the parameters - for (int i = 0; i < 3; i++) - { - VSH_IMD_PARAMETER *pParameter = &pIntermediate->Parameters[i]; - if(pParameter->Active) - { - VshWriteParameter(pParameter, pDisassembly, &DisassemblyPos); - } - } - DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "\n"); - } - *(pDisassembly + DisassemblyPos) = 0; -} - -static void VshAddParameter(VSH_PARAMETER *pParameter, - boolean a0x, - VSH_IMD_PARAMETER *pIntermediateParameter) -{ - pIntermediateParameter->Parameter = *pParameter; - pIntermediateParameter->Active = TRUE; - pIntermediateParameter->IsA0X = a0x; -} - -static void VshAddParameters(VSH_SHADER_INSTRUCTION *pInstruction, - VSH_ILU ILU, - VSH_MAC MAC, - VSH_IMD_PARAMETER *pParameters) -{ - uint08 ParamCount = 0; - VSH_OPCODE_PARAMS* pParams = VshGetOpCodeParams(ILU, MAC); - - // param A - if(pParams->A) - { - VshAddParameter(&pInstruction->A, pInstruction->a0x, &pParameters[ParamCount]); - ParamCount++; - } - - // param B - if(pParams->B) - { - VshAddParameter(&pInstruction->B, pInstruction->a0x, &pParameters[ParamCount]); - ParamCount++; - } - - // param C - if(pParams->C) - { - VshAddParameter(&pInstruction->C, pInstruction->a0x, &pParameters[ParamCount]); - ParamCount++; - } -} - -static void VshVerifyBufferBounds(VSH_XBOX_SHADER *pShader) -{ - if(pShader->IntermediateCount == VSH_MAX_INTERMEDIATE_COUNT) - { - CxbxKrnlCleanup("Shader exceeds conversion buffer!"); - } -} - -static VSH_INTERMEDIATE_FORMAT *VshNewIntermediate(VSH_XBOX_SHADER *pShader) -{ - VshVerifyBufferBounds(pShader); - - ZeroMemory(&pShader->Intermediate[pShader->IntermediateCount], sizeof(VSH_INTERMEDIATE_FORMAT)); - - return &pShader->Intermediate[pShader->IntermediateCount++]; -} - -static void VshInsertIntermediate(VSH_XBOX_SHADER *pShader, - VSH_INTERMEDIATE_FORMAT *pIntermediate, - uint16 Pos) -{ - VshVerifyBufferBounds(pShader); - - for (int i = pShader->IntermediateCount; i >= Pos; i--) - { - pShader->Intermediate[i + 1] = pShader->Intermediate[i]; - } - pShader->Intermediate[Pos] = *pIntermediate; - pShader->IntermediateCount++; -} - -static void VshDeleteIntermediate(VSH_XBOX_SHADER *pShader, - uint16 Pos) -{ - for (int i = Pos; i < (pShader->IntermediateCount - 1); i++) - { - pShader->Intermediate[i] = pShader->Intermediate[i + 1]; - } - pShader->IntermediateCount--; -} - -static boolean VshAddInstructionMAC_R(VSH_SHADER_INSTRUCTION *pInstruction, - VSH_XBOX_SHADER *pShader, - boolean IsCombined) -{ - VSH_INTERMEDIATE_FORMAT *pIntermediate; - if(!HasMACR(pInstruction)) - { - return FALSE; - } - - pIntermediate = VshNewIntermediate(pShader); - pIntermediate->IsCombined = IsCombined; - - // Opcode - pIntermediate->InstructionType = IMD_MAC; - pIntermediate->MAC = pInstruction->MAC; - - // Output param - pIntermediate->Output.Type = IMD_OUTPUT_R; - pIntermediate->Output.Address = pInstruction->Output.MACRAddress; - memcpy(pIntermediate->Output.Mask, pInstruction->Output.MACRMask, sizeof(boolean) * 4); - - // Other parameters - VshAddParameters(pInstruction, ILU_NOP, pInstruction->MAC, pIntermediate->Parameters); - - return TRUE; -} - -static boolean VshAddInstructionMAC_O(VSH_SHADER_INSTRUCTION* pInstruction, - VSH_XBOX_SHADER *pShader, - boolean IsCombined) -{ - VSH_INTERMEDIATE_FORMAT *pIntermediate; - if(!HasMACO(pInstruction)) - { - return FALSE; - } - - pIntermediate = VshNewIntermediate(pShader); - pIntermediate->IsCombined = IsCombined; - - // Opcode - pIntermediate->InstructionType = IMD_MAC; - pIntermediate->MAC = pInstruction->MAC; - - // Output param - pIntermediate->Output.Type = pInstruction->Output.OutputType == OUTPUT_C ? IMD_OUTPUT_C : IMD_OUTPUT_O; - pIntermediate->Output.Address = pInstruction->Output.OutputAddress; - memcpy(pIntermediate->Output.Mask, pInstruction->Output.OutputMask, sizeof(boolean) * 4); - - // Other parameters - VshAddParameters(pInstruction, ILU_NOP, pInstruction->MAC, pIntermediate->Parameters); - - return TRUE; -} - -static boolean VshAddInstructionMAC_ARL(VSH_SHADER_INSTRUCTION *pInstruction, - VSH_XBOX_SHADER *pShader, - boolean IsCombined) -{ - VSH_INTERMEDIATE_FORMAT *pIntermediate; - if(!HasMACARL(pInstruction)) - { - return FALSE; - } - - pIntermediate = VshNewIntermediate(pShader); - pIntermediate->IsCombined = IsCombined; - - // Opcode - pIntermediate->InstructionType = IMD_MAC; - pIntermediate->MAC = pInstruction->MAC; - - // Output param - pIntermediate->Output.Type = IMD_OUTPUT_A0X; - pIntermediate->Output.Address = pInstruction->Output.OutputAddress; - - // Other parameters - VshAddParameters(pInstruction, ILU_NOP, pInstruction->MAC, pIntermediate->Parameters); - - return TRUE; -} - -static boolean VshAddInstructionILU_R(VSH_SHADER_INSTRUCTION *pInstruction, - VSH_XBOX_SHADER *pShader, - boolean IsCombined) -{ - VSH_INTERMEDIATE_FORMAT *pIntermediate; - if(!HasILUR(pInstruction)) - { - return FALSE; - } - - pIntermediate = VshNewIntermediate(pShader); - pIntermediate->IsCombined = IsCombined; - - // Opcode - pIntermediate->InstructionType = IMD_ILU; - pIntermediate->ILU = pInstruction->ILU; - - // Output param - pIntermediate->Output.Type = IMD_OUTPUT_R; - // If this is a combined instruction, only r1 is allowed (R address should not be used) - pIntermediate->Output.Address = IsCombined ? 1 : pInstruction->Output.ILURAddress; - memcpy(pIntermediate->Output.Mask, pInstruction->Output.ILURMask, sizeof(boolean) * 4); - - // Other parameters - VshAddParameters(pInstruction, pInstruction->ILU, MAC_NOP, pIntermediate->Parameters); - - return TRUE; -} - -static boolean VshAddInstructionILU_O(VSH_SHADER_INSTRUCTION *pInstruction, - VSH_XBOX_SHADER *pShader, - boolean IsCombined) -{ - VSH_INTERMEDIATE_FORMAT *pIntermediate; - if(!HasILUO(pInstruction)) - { - return FALSE; - } - - pIntermediate = VshNewIntermediate(pShader); - pIntermediate->IsCombined = IsCombined; - - // Opcode - pIntermediate->InstructionType = IMD_ILU; - pIntermediate->ILU = pInstruction->ILU; - - // Output param - pIntermediate->Output.Type = pInstruction->Output.OutputType == OUTPUT_C ? IMD_OUTPUT_C : IMD_OUTPUT_O; - pIntermediate->Output.Address = pInstruction->Output.OutputAddress; - memcpy(pIntermediate->Output.Mask, pInstruction->Output.OutputMask, sizeof(boolean) * 4); - - // Other parameters - VshAddParameters(pInstruction, pInstruction->ILU, MAC_NOP, pIntermediate->Parameters); - - return TRUE; -} - -static void VshConvertToIntermediate(VSH_SHADER_INSTRUCTION *pInstruction, - VSH_XBOX_SHADER *pShader) -{ - // Five types of instructions: - // MAC - // - // ILU - // - // MAC - // +ILU - // - // MAC - // +MAC - // +ILU - // - // MAC - // +ILU - // +ILU - boolean IsCombined = FALSE; - - if(VshAddInstructionMAC_R(pInstruction, pShader, IsCombined)) - { - if(HasMACO(pInstruction) || - HasILUR(pInstruction) || - HasILUO(pInstruction)) - { - IsCombined = TRUE; - } - } - if(VshAddInstructionMAC_O(pInstruction, pShader, IsCombined)) - { - if(HasILUR(pInstruction) || - HasILUO(pInstruction)) - { - IsCombined = TRUE; - } - } - // Special case, arl (mov a0.x, ...) - if(VshAddInstructionMAC_ARL(pInstruction, pShader, IsCombined)) - { - if(HasILUR(pInstruction) || - HasILUO(pInstruction)) - { - IsCombined = TRUE; - } - } - if(VshAddInstructionILU_R(pInstruction, pShader, IsCombined)) - { - if(HasILUO(pInstruction)) - { - IsCombined = TRUE; - } - } - (void)VshAddInstructionILU_O(pInstruction, pShader, IsCombined); -} - -static inline void VshSetSwizzle(VSH_IMD_PARAMETER *pParameter, - VSH_SWIZZLE x, - VSH_SWIZZLE y, - VSH_SWIZZLE z, - VSH_SWIZZLE w) -{ - pParameter->Parameter.Swizzle[0] = x; - pParameter->Parameter.Swizzle[1] = y; - pParameter->Parameter.Swizzle[2] = z; - pParameter->Parameter.Swizzle[3] = w; -} - -static inline void VshSetOutputMask(VSH_IMD_OUTPUT* pOutput, - boolean MaskX, - boolean MaskY, - boolean MaskZ, - boolean MaskW) -{ - pOutput->Mask[0] = MaskX; - pOutput->Mask[1] = MaskY; - pOutput->Mask[2] = MaskZ; - pOutput->Mask[3] = MaskW; -} -/* - mul oPos.xyz, r12, c-38 - +rcc r1.x, r12.w - - mad oPos.xyz, r12, r1.x, c-37 -*/ -static void VshRemoveScreenSpaceInstructions(VSH_XBOX_SHADER *pShader) -{ - int16 PosC38 = -1; - int deleted = 0; - - for (int i = 0; i < pShader->IntermediateCount; i++) - { - VSH_INTERMEDIATE_FORMAT* pIntermediate = &pShader->Intermediate[i]; - - for (int k = 0; k < 3; k++) - { - if(pIntermediate->Parameters[k].Active) - { - if(pIntermediate->Parameters[k].Parameter.ParameterType == PARAM_C && - !pIntermediate->Parameters[k].IsA0X) - { - if(pIntermediate->Parameters[k].Parameter.Address == -37) - { - // Found c-37, remove the instruction - if(k == 2 && - pIntermediate->Parameters[1].Active && - pIntermediate->Parameters[1].Parameter.ParameterType == PARAM_R) - { - DbgVshPrintf("PosC38 = %d i = %d\n", PosC38, i); - for (int j = (i-1); j >= 0; j--) - { - VSH_INTERMEDIATE_FORMAT* pIntermediate1W = &pShader->Intermediate[j]; - // Time to start searching for +rcc r#.x, r12.w - if(pIntermediate1W->InstructionType == IMD_ILU && - pIntermediate1W->ILU == ILU_RCC && - pIntermediate1W->Output.Type == IMD_OUTPUT_R && - pIntermediate1W->Output.Address == - pIntermediate->Parameters[1].Parameter.Address) - { - DbgVshPrintf("Deleted +rcc r1.x, r12.w\n"); - VshDeleteIntermediate(pShader, j); - deleted++; - i--; - //j--; - break; - } - } - } - VshDeleteIntermediate(pShader, i); - deleted++; - i--; - DbgVshPrintf("Deleted mad oPos.xyz, r12, r1.x, c-37\n"); - break; - } - else if(pIntermediate->Parameters[k].Parameter.Address == -38) - { - VshDeleteIntermediate(pShader, i); - PosC38 = i; - deleted++; - i--; - DbgVshPrintf("Deleted mul oPos.xyz, r12, c-38\n"); - } - } - } - } - } - - // If we couldn't find the generic screen space transformation we're - // assuming that the shader writes direct screen coordinates that must be - // normalized. This hack will fail if (a) the shader uses custom screen - // space transformation, (b) reads r10 or r11 after we have written to - // them, or (c) doesn't reserve c-38 and c-37 for scale and offset. - if(deleted != 3) - { - EmuWarning("Applying screen space vertex shader patching hack!"); - for (int i = 0; i < pShader->IntermediateCount; i++) - { - VSH_INTERMEDIATE_FORMAT* pIntermediate = &pShader->Intermediate[i]; - - // Find instructions outputting to oPos. - if( pIntermediate->Output.Type == IMD_OUTPUT_O && - pIntermediate->Output.Address == OREG_OPOS) - { - // Redirect output to r11. - pIntermediate->Output.Type = IMD_OUTPUT_R; - pIntermediate->Output.Address = 11; - - // Scale r11 to r10. (mul r10.[mask], r11, c58) - VSH_INTERMEDIATE_FORMAT MulIntermediate; - MulIntermediate.IsCombined = FALSE; - MulIntermediate.InstructionType = IMD_MAC; - MulIntermediate.MAC = MAC_MUL; - MulIntermediate.Output.Type = IMD_OUTPUT_R; - MulIntermediate.Output.Address = 10; - MulIntermediate.Output.Mask[0] = pIntermediate->Output.Mask[0]; - MulIntermediate.Output.Mask[1] = pIntermediate->Output.Mask[1]; - MulIntermediate.Output.Mask[2] = pIntermediate->Output.Mask[2]; - MulIntermediate.Output.Mask[3] = pIntermediate->Output.Mask[3]; - MulIntermediate.Parameters[0].Active = TRUE; - MulIntermediate.Parameters[0].IsA0X = FALSE; - MulIntermediate.Parameters[0].Parameter.ParameterType = PARAM_R; - MulIntermediate.Parameters[0].Parameter.Address = 11; - MulIntermediate.Parameters[0].Parameter.Neg = FALSE; - VshSetSwizzle(&MulIntermediate.Parameters[0], SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W); - MulIntermediate.Parameters[1].Active = TRUE; - MulIntermediate.Parameters[1].IsA0X = FALSE; - MulIntermediate.Parameters[1].Parameter.ParameterType = PARAM_C; - MulIntermediate.Parameters[1].Parameter.Address = ConvertCRegister(58); - MulIntermediate.Parameters[1].Parameter.Neg = FALSE; - VshSetSwizzle(&MulIntermediate.Parameters[1], SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W); - MulIntermediate.Parameters[2].Active = FALSE; - VshInsertIntermediate(pShader, &MulIntermediate, ++i); - - // Add offset with r10 to oPos (add oPos.[mask], r10, c59) - VSH_INTERMEDIATE_FORMAT AddIntermediate = MulIntermediate; - AddIntermediate.MAC = MAC_ADD; - AddIntermediate.Output.Type = IMD_OUTPUT_O; - AddIntermediate.Output.Address = OREG_OPOS; - AddIntermediate.Parameters[0].Parameter.ParameterType = PARAM_R; - AddIntermediate.Parameters[0].Parameter.Address = 10; - AddIntermediate.Parameters[1].Parameter.Address = ConvertCRegister(59); - VshInsertIntermediate(pShader, &AddIntermediate, ++i); - } - } - } -} - -// Converts the intermediate format vertex shader to DirectX 8 format -static boolean VshConvertShader(VSH_XBOX_SHADER *pShader, - boolean bNoReservedConstants) -{ - boolean RUsage[13] = { FALSE }; - // TODO: What about state shaders and such? - pShader->ShaderHeader.Version = VERSION_VS; - - // Search for the screen space instructions, and remove them - if(!bNoReservedConstants) - { - VshRemoveScreenSpaceInstructions(pShader); - } - - // TODO: Add routine for compacting r register usage so that at least one is freed (two if dph and r12) - - for (int i = 0; i < pShader->IntermediateCount; i++) - { - VSH_INTERMEDIATE_FORMAT* pIntermediate = &pShader->Intermediate[i]; - // Combining not supported in vs.1.1 - pIntermediate->IsCombined = FALSE; - - /* - if(pIntermediate->Output.Type == IMD_OUTPUT_O && pIntermediate->Output.Address == OREG_OFOG) - { - // The PC shader assembler doesn't like masks on scalar registers - VshSetOutputMask(&pIntermediate->Output, TRUE, TRUE, TRUE, TRUE); - }*/ - - if(pIntermediate->InstructionType == IMD_ILU && pIntermediate->ILU == ILU_RCC) - { - // Convert rcc to rcp - pIntermediate->ILU = ILU_RCP; - } - - if(pIntermediate->Output.Type == IMD_OUTPUT_R) - { - RUsage[pIntermediate->Output.Address] = TRUE; - } - // Make constant registers range from 0 to 192 instead of -96 to 96 - if(pIntermediate->Output.Type == IMD_OUTPUT_C) - { - pIntermediate->Output.Address += 96; - } - - for (int j = 0; j < 3; j++) - { - if(pIntermediate->Parameters[j].Active) - { - if(pIntermediate->Parameters[j].Parameter.ParameterType == PARAM_R) - { - RUsage[pIntermediate->Parameters[j].Parameter.Address] = TRUE; - } - // Make constant registers range from 0 to 192 instead of -96 to 96 - if(pIntermediate->Parameters[j].Parameter.ParameterType == PARAM_C) - { - pIntermediate->Parameters[j].Parameter.Address += 96; - } - } - } - - if(pIntermediate->InstructionType == IMD_MAC && pIntermediate->MAC == MAC_DPH) - { - // Replace dph with dp3 and add - if(pIntermediate->Output.Type != IMD_OUTPUT_R) - { - // TODO: Complete dph support - EmuWarning("Can't simulate dph for other than output r registers (yet)\n"); - return FALSE; - } - VSH_INTERMEDIATE_FORMAT TmpIntermediate = *pIntermediate; - pIntermediate->MAC = MAC_DP3; - TmpIntermediate.MAC = MAC_ADD; - TmpIntermediate.Parameters[0].IsA0X = FALSE; - TmpIntermediate.Parameters[0].Parameter.ParameterType = PARAM_R; - TmpIntermediate.Parameters[0].Parameter.Address = TmpIntermediate.Output.Address; - TmpIntermediate.Parameters[0].Parameter.Neg = FALSE; - VshSetSwizzle(&TmpIntermediate.Parameters[0], SWIZZLE_W, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W); - VshSetSwizzle(&TmpIntermediate.Parameters[1], SWIZZLE_W, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W); - VshSetOutputMask(&TmpIntermediate.Output, FALSE, FALSE, FALSE, TRUE); - VshInsertIntermediate(pShader, &TmpIntermediate, i + 1); - i++; - } - } - int16 R12Replacement = -1; - if(RUsage[12]) - { - // Sigh, they absolutely had to use r12, didn't they? - for (int i = 11; i >= 0; i--) - { - if(!RUsage[i]) - { - R12Replacement = i; - break; - } - } - if(R12Replacement == -1) - { - EmuWarning("Vertex shader uses all r registers, including r12; impossible to convert!"); - return FALSE; - } - for (int j = 0; j < pShader->IntermediateCount; j++) - { - VSH_INTERMEDIATE_FORMAT* pIntermediate = &pShader->Intermediate[j]; - if(pIntermediate->Output.Type == IMD_OUTPUT_O && - pIntermediate->Output.Address == OREG_OPOS) - { - // Found instruction writing to oPos - pIntermediate->Output.Type = IMD_OUTPUT_R; - pIntermediate->Output.Address = R12Replacement; - } - - for (int k = 0; k < 3; k++) - { - if(pIntermediate->Parameters[k].Active) - { - if(pIntermediate->Parameters[k].Parameter.ParameterType == PARAM_R && - pIntermediate->Parameters[k].Parameter.Address == 12) - { - // Found a r12 used as a parameter; replace - pIntermediate->Parameters[k].Parameter.Address = R12Replacement; - } - else if(pIntermediate->Parameters[k].Parameter.ParameterType == PARAM_C && - pIntermediate->Parameters[k].Parameter.Address == 58 && - !pIntermediate->Parameters[k].IsA0X) - { - // Found c-38, replace it with r12.w - pIntermediate->Parameters[k].Parameter.ParameterType = PARAM_R; - pIntermediate->Parameters[k].Parameter.Address = R12Replacement; - VshSetSwizzle(&pIntermediate->Parameters[k], SWIZZLE_W, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W); - } - } - } - } - // Insert mov oPos, r## in the end - VSH_INTERMEDIATE_FORMAT *pOPosWriteBack = VshNewIntermediate(pShader); - pOPosWriteBack->InstructionType = IMD_ILU; - pOPosWriteBack->ILU = ILU_MOV; - pOPosWriteBack->MAC = MAC_NOP; - pOPosWriteBack->Output.Type = IMD_OUTPUT_O; - pOPosWriteBack->Output.Address = OREG_OPOS; - VshSetOutputMask(&pOPosWriteBack->Output, TRUE, TRUE, TRUE, TRUE); - pOPosWriteBack->Parameters[0].Active = TRUE; - pOPosWriteBack->Parameters[0].Parameter.ParameterType = PARAM_R; - pOPosWriteBack->Parameters[0].Parameter.Address = R12Replacement; - VshSetSwizzle(&pOPosWriteBack->Parameters[0], SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W); - } - return TRUE; -} - -// **************************************************************************** -// * Vertex shader declaration recompiler -// **************************************************************************** - -typedef struct _VSH_TYPE_PATCH_DATA -{ - DWORD NbrTypes; - UINT Types[256]; -} -VSH_TYPE_PATCH_DATA; - -typedef struct _VSH_STREAM_PATCH_DATA -{ - DWORD NbrStreams; - XTL::STREAM_DYNAMIC_PATCH pStreamPatches[256]; -} -VSH_STREAM_PATCH_DATA; - -typedef struct _VSH_PATCH_DATA -{ - boolean NeedPatching; - DWORD ConvertedStride; - VSH_TYPE_PATCH_DATA TypePatchData; - VSH_STREAM_PATCH_DATA StreamPatchData; -} -VSH_PATCH_DATA; - -// VERTEX SHADER -#define DEF_VSH_END 0xFFFFFFFF -#define DEF_VSH_NOP 0x00000000 - -static DWORD VshGetDeclarationSize(DWORD *pDeclaration) -{ - DWORD Pos = 0; - while (*(pDeclaration + Pos) != DEF_VSH_END) - { - Pos++; - } - return (Pos + 1) * sizeof(DWORD); -} - -DWORD Xb2PCRegisterType(DWORD VertexRegister) -{ - DWORD PCRegisterType; - switch(VertexRegister) - { - case -1: - DbgVshPrintf("D3DVSDE_VERTEX /* xbox ext. */"); - PCRegisterType = -1; - break; - case 0: - DbgVshPrintf("D3DVSDE_POSITION"); - PCRegisterType = D3DVSDE_POSITION; - break; - case 1: - DbgVshPrintf("D3DVSDE_BLENDWEIGHT"); - PCRegisterType = D3DVSDE_BLENDWEIGHT; - break; - case 2: - DbgVshPrintf("D3DVSDE_NORMAL"); - PCRegisterType = D3DVSDE_NORMAL; - break; - case 3: - DbgVshPrintf("D3DVSDE_DIFFUSE"); - PCRegisterType = D3DVSDE_DIFFUSE; - break; - case 4: - DbgVshPrintf("D3DVSDE_SPECULAR"); - PCRegisterType = D3DVSDE_SPECULAR; - break; - case 5: - DbgVshPrintf("D3DVSDE_FOG /* xbox ext. */"); - PCRegisterType = -1; - break; - case 7: - DbgVshPrintf("D3DVSDE_BACKDIFFUSE /* xbox ext. */"); - PCRegisterType = -1; - break; - case 8: - DbgVshPrintf("D3DVSDE_BACKSPECULAR /* xbox ext. */"); - PCRegisterType = -1; - break; - case 9: - DbgVshPrintf("D3DVSDE_TEXCOORD0"); - PCRegisterType = D3DVSDE_TEXCOORD0; - break; - case 10: - DbgVshPrintf("D3DVSDE_TEXCOORD1"); - PCRegisterType = D3DVSDE_TEXCOORD1; - break; - case 11: - DbgVshPrintf("D3DVSDE_TEXCOORD2"); - PCRegisterType = D3DVSDE_TEXCOORD2; - break; - case 12: - DbgVshPrintf("D3DVSDE_TEXCOORD3"); - PCRegisterType = D3DVSDE_TEXCOORD3; - break; - default: - DbgVshPrintf("%d /* unknown register */", VertexRegister); - PCRegisterType = -1; - break; - } - return PCRegisterType; -} - -static inline DWORD VshGetTokenType(DWORD Token) -{ - return (Token & D3DVSD_TOKENTYPEMASK) >> D3DVSD_TOKENTYPESHIFT; -} - -static inline DWORD VshGetVertexRegister(DWORD Token) -{ - return (Token & D3DVSD_VERTEXREGMASK) >> D3DVSD_VERTEXREGSHIFT; -} - -static inline DWORD VshGetVertexRegisterIn(DWORD Token) -{ - return (Token & D3DVSD_VERTEXREGINMASK) >> D3DVSD_VERTEXREGINSHIFT; -} - -static inline DWORD VshGetVertexStream(DWORD Token) -{ - return (Token & D3DVSD_STREAMNUMBERMASK) >> D3DVSD_STREAMNUMBERSHIFT; -} - -static void VshConvertToken_NOP(DWORD *pToken) -{ - // D3DVSD_NOP - if(*pToken != DEF_VSH_NOP) - { - EmuWarning("Token NOP found, but extra parameters are given!\n"); - } - DbgVshPrintf("\tD3DVSD_NOP(),\n"); -} - -static DWORD VshConvertToken_CONSTMEM(DWORD *pToken) -{ - // D3DVSD_CONST - DbgVshPrintf("\tD3DVSD_CONST("); - - DWORD ConstantAddress = ((*pToken >> D3DVSD_CONSTADDRESSSHIFT) & 0xFF); - DWORD Count = (*pToken & D3DVSD_CONSTCOUNTMASK) >> D3DVSD_CONSTCOUNTSHIFT; - - DbgVshPrintf("%d, %d),\n", ConstantAddress, Count); - - //pToken = D3DVSD_CONST(ConstantAddress, Count); - - for (uint i = 0; i < Count; i++) - { - DbgVshPrintf("\t0x%08X,\n", pToken); - } - return Count; -} - -static void VshConverToken_TESSELATOR(DWORD *pToken, - boolean IsFixedFunction) -{ - using namespace XTL; - - // TODO: Investigate why Xb2PCRegisterType is only used for fixed function vertex shaders - // D3DVSD_TESSUV - if(*pToken & 0x10000000) - { - XTL::DWORD VertexRegister = VshGetVertexRegister(*pToken); - XTL::DWORD NewVertexRegister = VertexRegister; - - DbgVshPrintf("\tD3DVSD_TESSUV("); - - if(IsFixedFunction) - { - NewVertexRegister = Xb2PCRegisterType(VertexRegister); - } - else - { - DbgVshPrintf("%d", NewVertexRegister); - } - - DbgVshPrintf("),\n"); - - *pToken = D3DVSD_TESSUV(NewVertexRegister); - } - // D3DVSD_TESSNORMAL - else - { - XTL::DWORD VertexRegisterIn = VshGetVertexRegisterIn(*pToken); - XTL::DWORD VertexRegisterOut = VshGetVertexRegister(*pToken); - - XTL::DWORD NewVertexRegisterIn = VertexRegisterIn; - XTL::DWORD NewVertexRegisterOut = VertexRegisterOut; - - DbgVshPrintf("\tD3DVSD_TESSNORMAL("); - - if(IsFixedFunction) - { - NewVertexRegisterIn = Xb2PCRegisterType(VertexRegisterIn); - } - else - { - DbgVshPrintf("%d", NewVertexRegisterIn); - } - - DbgVshPrintf(", "); - - if(IsFixedFunction) - { - NewVertexRegisterOut = Xb2PCRegisterType(VertexRegisterOut); - } - else - { - DbgVshPrintf("%d", NewVertexRegisterOut); - } - - DbgVshPrintf("),\n"); - *pToken = D3DVSD_TESSNORMAL(NewVertexRegisterIn, NewVertexRegisterOut); - } -} - -static boolean VshAddStreamPatch(VSH_PATCH_DATA *pPatchData) -{ - int CurrentStream = pPatchData->StreamPatchData.NbrStreams - 1; - - if(CurrentStream >= 0) - { - DbgVshPrintf("NeedPatching: %d\n", pPatchData->NeedPatching); - - XTL::STREAM_DYNAMIC_PATCH* pStreamPatch = &pPatchData->StreamPatchData.pStreamPatches[CurrentStream]; - - pStreamPatch->ConvertedStride = pPatchData->ConvertedStride; - pStreamPatch->NbrTypes = pPatchData->TypePatchData.NbrTypes; - pStreamPatch->NeedPatch = pPatchData->NeedPatching; - pStreamPatch->pTypes = (UINT *)CxbxMalloc(pPatchData->TypePatchData.NbrTypes * sizeof(VSH_TYPE_PATCH_DATA)); - memcpy(pStreamPatch->pTypes, pPatchData->TypePatchData.Types, pPatchData->TypePatchData.NbrTypes * sizeof(VSH_TYPE_PATCH_DATA)); - - return TRUE; - } - return FALSE; -} - -static void VshConvertToken_STREAM(DWORD *pToken, - VSH_PATCH_DATA *pPatchData) -{ - // D3DVSD_STREAM_TESS - if(*pToken & D3DVSD_STREAMTESSMASK) - { - DbgVshPrintf("\tD3DVSD_STREAM_TESS(),\n"); - } - // D3DVSD_STREAM - else - { - XTL::DWORD StreamNumber = VshGetVertexStream(*pToken); - DbgVshPrintf("\tD3DVSD_STREAM(%d),\n", StreamNumber); - - // new stream - // copy current data to structure - if(VshAddStreamPatch(pPatchData)) - { - pPatchData->ConvertedStride = 0; - pPatchData->TypePatchData.NbrTypes = 0; - pPatchData->NeedPatching = FALSE; - } - - pPatchData->StreamPatchData.NbrStreams++; - } -} - -static void VshConvertToken_STREAMDATA_SKIP(DWORD *pToken) -{ - using namespace XTL; - - XTL::DWORD SkipCount = (*pToken & D3DVSD_SKIPCOUNTMASK) >> D3DVSD_SKIPCOUNTSHIFT; - DbgVshPrintf("\tD3DVSD_SKIP(%d),\n", SkipCount); -} - -static void VshConvertToken_STREAMDATA_SKIPBYTES(DWORD *pToken) -{ - using namespace XTL; - - XTL::DWORD SkipBytesCount = (*pToken & D3DVSD_SKIPCOUNTMASK) >> D3DVSD_SKIPCOUNTSHIFT; - DbgVshPrintf("\tD3DVSD_SKIPBYTES(%d), /* xbox ext. */\n", SkipBytesCount); - if(SkipBytesCount % sizeof(XTL::DWORD)) - { - EmuWarning("D3DVSD_SKIPBYTES can't be converted to D3DVSD_SKIP, not divisble by 4."); - } - *pToken = D3DVSD_SKIP(SkipBytesCount / sizeof(XTL::DWORD)); -} - -static void VshConvertToken_STREAMDATA_REG(DWORD *pToken, - boolean IsFixedFunction, - VSH_PATCH_DATA *pPatchData) -{ - using namespace XTL; - - DbgVshPrintf("\tD3DVSD_REG("); - - XTL::DWORD VertexRegister = VshGetVertexRegister(*pToken); - XTL::DWORD NewVertexRegister; - - if(IsFixedFunction) - { - NewVertexRegister = Xb2PCRegisterType(VertexRegister); - } - else - { - NewVertexRegister = VertexRegister; - DbgVshPrintf("%d", NewVertexRegister); - } - - DbgVshPrintf(", "); - - XTL::DWORD DataType = (*pToken >> D3DVSD_DATATYPESHIFT) & 0xFF; - XTL::DWORD NewDataType = 0; - - // save patching information - pPatchData->TypePatchData.Types[pPatchData->TypePatchData.NbrTypes] = DataType; - pPatchData->TypePatchData.NbrTypes++; - - switch(DataType) - { - case 0x12: - DbgVshPrintf("D3DVSDT_FLOAT1"); - NewDataType = D3DVSDT_FLOAT1; - pPatchData->ConvertedStride += sizeof(FLOAT); - break; - case 0x22: - DbgVshPrintf("D3DVSDT_FLOAT2"); - NewDataType = D3DVSDT_FLOAT2; - pPatchData->ConvertedStride += 2*sizeof(FLOAT); - break; - case 0x32: - DbgVshPrintf("D3DVSDT_FLOAT3"); - NewDataType = D3DVSDT_FLOAT3; - pPatchData->ConvertedStride += 3*sizeof(FLOAT); - break; - case 0x42: - DbgVshPrintf("D3DVSDT_FLOAT4"); - NewDataType = D3DVSDT_FLOAT4; - pPatchData->ConvertedStride += 4*sizeof(FLOAT); - break; - case 0x40: - DbgVshPrintf("D3DVSDT_D3DCOLOR"); - NewDataType = D3DVSDT_D3DCOLOR; - pPatchData->ConvertedStride += sizeof(D3DCOLOR); - break; - case 0x25: - DbgVshPrintf("D3DVSDT_SHORT2"); - NewDataType = D3DVSDT_SHORT2; - pPatchData->ConvertedStride += 2*sizeof(XTL::SHORT); - break; - case 0x45: - DbgVshPrintf("D3DVSDT_SHORT4"); - NewDataType = D3DVSDT_SHORT4; - pPatchData->ConvertedStride += 4*sizeof(XTL::SHORT); - break; - case 0x11: - DbgVshPrintf("D3DVSDT_NORMSHORT1 /* xbox ext. */"); - NewDataType = D3DVSDT_SHORT2; // hmm, emulation? - pPatchData->ConvertedStride += 2*sizeof(XTL::SHORT); - pPatchData->NeedPatching = TRUE; - break; - case 0x21: - DbgVshPrintf("D3DVSDT_NORMSHORT2 /* xbox ext. */"); - NewDataType = D3DVSDT_SHORT2; - pPatchData->ConvertedStride += 2*sizeof(XTL::SHORT); - pPatchData->NeedPatching = TRUE; - break; - case 0x31: - DbgVshPrintf("D3DVSDT_NORMSHORT3 /* xbox ext. nsp */"); - NewDataType = D3DVSDT_SHORT4; - pPatchData->ConvertedStride += 4*sizeof(XTL::SHORT); - pPatchData->NeedPatching = TRUE; - break; - case 0x41: - DbgVshPrintf("D3DVSDT_NORMSHORT4 /* xbox ext. */"); - NewDataType = D3DVSDT_SHORT4; - pPatchData->ConvertedStride += 4*sizeof(XTL::SHORT); - pPatchData->NeedPatching = TRUE; - break; - case 0x16: - DbgVshPrintf("D3DVSDT_NORMPACKED3 /* xbox ext. nsp */"); - NewDataType = D3DVSDT_FLOAT3;//0xFF; //32bit - pPatchData->ConvertedStride += 3*sizeof(FLOAT); - pPatchData->NeedPatching = TRUE; - break; - case 0x15: - DbgVshPrintf("D3DVSDT_SHORT1 /* xbox ext. nsp */"); - NewDataType = D3DVSDT_SHORT2; - pPatchData->ConvertedStride += 2*sizeof(XTL::SHORT); - pPatchData->NeedPatching = TRUE; - break; - case 0x35: - DbgVshPrintf("D3DVSDT_SHORT3 /* xbox ext. nsp */"); - NewDataType = D3DVSDT_SHORT4; - pPatchData->ConvertedStride += 4*sizeof(XTL::SHORT); - pPatchData->NeedPatching = TRUE; - break; - case 0x14: - DbgVshPrintf("D3DVSDT_PBYTE1 /* xbox ext. nsp */"); - NewDataType = D3DVSDT_FLOAT1; - pPatchData->ConvertedStride += 1*sizeof(FLOAT); - pPatchData->NeedPatching = TRUE; - break; - case 0x24: - DbgVshPrintf("D3DVSDT_PBYTE2 /* xbox ext. nsp */"); - NewDataType = D3DVSDT_FLOAT2; - pPatchData->ConvertedStride += 2*sizeof(FLOAT); - pPatchData->NeedPatching = TRUE; - break; - case 0x34: - DbgVshPrintf("D3DVSDT_PBYTE3 /* xbox ext. nsp */"); - NewDataType = D3DVSDT_FLOAT3; - pPatchData->ConvertedStride += 3*sizeof(FLOAT); - pPatchData->NeedPatching = TRUE; - break; - case 0x44: - DbgVshPrintf("D3DVSDT_PBYTE4 /* xbox ext. */"); - NewDataType = D3DVSDT_FLOAT4; - pPatchData->ConvertedStride += 4*sizeof(FLOAT); - break; - case 0x72: - DbgVshPrintf("D3DVSDT_FLOAT2H /* xbox ext. */"); - NewDataType = D3DVSDT_FLOAT3; - pPatchData->ConvertedStride += 3*sizeof(FLOAT); - pPatchData->NeedPatching = TRUE; - break; - case 0x02: - DbgVshPrintf("D3DVSDT_NONE /* xbox ext. nsp */"); - NewDataType = 0xFF; - break; - default: - DbgVshPrintf("Unknown data type for D3DVSD_REG: 0x%02X\n", DataType); - break; - } - *pToken = D3DVSD_REG(NewVertexRegister, NewDataType); - - DbgVshPrintf("),\n"); - - if(NewDataType == 0xFF) - { - EmuWarning("/* WARNING: Fatal type mismatch, no fitting type! */\n"); - } -} - -static void VshConvertToken_STREAMDATA(DWORD *pToken, - boolean IsFixedFunction, - VSH_PATCH_DATA *pPatchData) -{ - using namespace XTL; - - // D3DVSD_SKIP - if(*pToken & 0x10000000) - { - VshConvertToken_STREAMDATA_SKIP(pToken); - } - // D3DVSD_SKIPBYTES - else if(*pToken & 0x18000000) - { - VshConvertToken_STREAMDATA_SKIPBYTES(pToken); - } - // D3DVSD_REG - else - { - VshConvertToken_STREAMDATA_REG(pToken, IsFixedFunction, pPatchData); - } -} - -static DWORD VshRecompileToken(DWORD *pToken, - boolean IsFixedFunction, - VSH_PATCH_DATA *pPatchData) -{ - using namespace XTL; - - XTL::DWORD Step = 1; - - switch(VshGetTokenType(*pToken)) - { - case D3DVSD_TOKEN_NOP: - VshConvertToken_NOP(pToken); - break; - case D3DVSD_TOKEN_STREAM: - { - VshConvertToken_STREAM(pToken, pPatchData); - break; - } - case D3DVSD_TOKEN_STREAMDATA: - { - VshConvertToken_STREAMDATA(pToken, IsFixedFunction, pPatchData); - break; - } - case D3DVSD_TOKEN_TESSELLATOR: - { - VshConverToken_TESSELATOR(pToken, IsFixedFunction); - break; - } - case D3DVSD_TOKEN_CONSTMEM: - { - Step = VshConvertToken_CONSTMEM(pToken); - break; - } - default: - DbgVshPrintf("Unknown token type: %d\n", VshGetTokenType(*pToken)); - break; - } - - return Step; -} - -DWORD XTL::EmuRecompileVshDeclaration -( - DWORD *pDeclaration, - DWORD **ppRecompiledDeclaration, - DWORD *pDeclarationSize, - boolean IsFixedFunction, - VERTEX_DYNAMIC_PATCH *pVertexDynamicPatch -) -{ - // First of all some info: - // We have to figure out which flags are set and then - // we have to patch their params - - // some token values - // 0xFFFFFFFF - end of the declaration - // 0x00000000 - nop (means that this value is ignored) - - // Calculate size of declaration - DWORD DeclarationSize = VshGetDeclarationSize(pDeclaration); - *ppRecompiledDeclaration = (DWORD *)CxbxMalloc(DeclarationSize); - DWORD *pRecompiled = *ppRecompiledDeclaration; - memcpy(pRecompiled, pDeclaration, DeclarationSize); - *pDeclarationSize = DeclarationSize; - - // TODO: Put these in one struct - VSH_PATCH_DATA PatchData = { 0 }; - - DbgVshPrintf("DWORD dwVSHDecl[] =\n{\n"); - - while (*pRecompiled != DEF_VSH_END) - { - DWORD Step = VshRecompileToken(pRecompiled, IsFixedFunction, &PatchData); - pRecompiled += Step; - } - DbgVshPrintf("\tD3DVSD_END()\n};\n"); - - VshAddStreamPatch(&PatchData); - - DbgVshPrintf("NbrStreams: %d\n", PatchData.StreamPatchData.NbrStreams); - - // Copy the patches to the vertex shader struct - DWORD StreamsSize = PatchData.StreamPatchData.NbrStreams * sizeof(STREAM_DYNAMIC_PATCH); - pVertexDynamicPatch->NbrStreams = PatchData.StreamPatchData.NbrStreams; - pVertexDynamicPatch->pStreamPatches = (STREAM_DYNAMIC_PATCH *)CxbxMalloc(StreamsSize); - memcpy(pVertexDynamicPatch->pStreamPatches, - PatchData.StreamPatchData.pStreamPatches, - StreamsSize); - - return D3D_OK; -} - -// recompile xbox vertex shader function -extern HRESULT XTL::EmuRecompileVshFunction -( - DWORD *pFunction, - LPD3DXBUFFER *ppRecompiled, - DWORD *pOriginalSize, - boolean bNoReservedConstants -) -{ - VSH_SHADER_HEADER *pShaderHeader = (VSH_SHADER_HEADER*)pFunction; - DWORD *pToken; - boolean EOI = false; - VSH_XBOX_SHADER *pShader = (VSH_XBOX_SHADER*)CxbxMalloc(sizeof(VSH_XBOX_SHADER)); - HRESULT hRet = 0; - - // TODO: support this situation.. - if(pFunction == NULL) - return E_FAIL; - - *ppRecompiled = NULL; - *pOriginalSize = 0; - if(!pShader) - { - EmuWarning("Couldn't allocate memory for vertex shader conversion buffer"); - hRet = E_OUTOFMEMORY; - } - memset(pShader, 0, sizeof(VSH_XBOX_SHADER)); - pShader->ShaderHeader = *pShaderHeader; - switch(pShaderHeader->Version) - { - case VERSION_XVS: - break; - case VERSION_XVSS: - EmuWarning("Might not support vertex state shaders?"); - hRet = E_FAIL; - break; - case VERSION_XVSW: - EmuWarning("Might not support vertex read/write shaders?"); - hRet = E_FAIL; - break; - default: - EmuWarning("Unknown vertex shader version 0x%02X\n", pShaderHeader->Version); - hRet = E_FAIL; - break; - } - - if(SUCCEEDED(hRet)) - { - - for (pToken = (DWORD*)((uint08*)pFunction + sizeof(VSH_SHADER_HEADER)); !EOI; pToken += VSH_INSTRUCTION_SIZE) - { - VSH_SHADER_INSTRUCTION Inst; - - VshParseInstruction(pToken, &Inst); - VshConvertToIntermediate(&Inst, pShader); - EOI = (boolean)VshGetField(pToken, FLD_FINAL); - } - - // The size of the shader is - *pOriginalSize = (DWORD)pToken - (DWORD)pFunction; - - char* pShaderDisassembly = (char*)CxbxMalloc(pShader->IntermediateCount * 50); // Should be plenty - DbgVshPrintf("-- Before conversion --\n"); - VshWriteShader(pShader, pShaderDisassembly, FALSE); - DbgVshPrintf("%s", pShaderDisassembly); - DbgVshPrintf("-----------------------\n"); - - VshConvertShader(pShader, bNoReservedConstants); - VshWriteShader(pShader, pShaderDisassembly, TRUE); - - DbgVshPrintf("-- After conversion ---\n"); - DbgVshPrintf("%s", pShaderDisassembly); - DbgVshPrintf("-----------------------\n"); - - // HACK: Azurik. Prevent Direct3D from trying to assemble this. - if(!strcmp(pShaderDisassembly, "vs.1.1\n")) - { - EmuWarning("Cannot assemble empty vertex shader!\n"); - hRet = D3DXERR_INVALIDDATA; - } - else - { - - hRet = D3DXAssembleShader(pShaderDisassembly, - strlen(pShaderDisassembly), - D3DXASM_SKIPVALIDATION, - NULL, - ppRecompiled, - NULL); - } - - if (FAILED(hRet)) - { - EmuWarning("Couldn't assemble recompiled vertex shader\n"); - } - - CxbxFree(pShaderDisassembly); - } - CxbxFree(pShader); - - return hRet; -} - -extern void XTL::FreeVertexDynamicPatch(VERTEX_SHADER *pVertexShader) -{ - for (DWORD i = 0; i < pVertexShader->VertexDynamicPatch.NbrStreams; i++) - { - CxbxFree(pVertexShader->VertexDynamicPatch.pStreamPatches[i].pTypes); - } - CxbxFree(pVertexShader->VertexDynamicPatch.pStreamPatches); - pVertexShader->VertexDynamicPatch.pStreamPatches = NULL; - pVertexShader->VertexDynamicPatch.NbrStreams = 0; -} - -extern boolean XTL::IsValidCurrentShader(void) -{ - DWORD Handle; - - EmuSwapFS(); - EmuIDirect3DDevice8_GetVertexShader(&Handle); - EmuSwapFS(); - if (VshHandleIsVertexShader(Handle)) - { - X_D3DVertexShader *pD3DVertexShader = (X_D3DVertexShader *)(Handle & 0x7FFFFFFF); - VERTEX_SHADER *pVertexShader = (VERTEX_SHADER *)pD3DVertexShader->Handle; - if (pVertexShader->Status != 0) - { - return FALSE; - } - /* - for (uint32 i = 0; i < pVertexShader->VertexDynamicPatch.NbrStreams; i++) - { - if (pVertexShader->VertexDynamicPatch.pStreamPatches[i].NeedPatch) - { - // Just for caching purposes - pVertexShader->Status = 0x80000001; - return FALSE; - } - } - */ - } - return TRUE; -} - -extern XTL::VERTEX_DYNAMIC_PATCH *XTL::VshGetVertexDynamicPatch(DWORD Handle) -{ - X_D3DVertexShader *pD3DVertexShader = VshHandleGetVertexShader(Handle); - VERTEX_SHADER *pVertexShader = (VERTEX_SHADER *)pD3DVertexShader->Handle; - - for (uint32 i = 0; i < pVertexShader->VertexDynamicPatch.NbrStreams; i++) - { - if (pVertexShader->VertexDynamicPatch.pStreamPatches[i].NeedPatch) - { - return &pVertexShader->VertexDynamicPatch; - } - } - return NULL; -} \ No newline at end of file diff --git a/src/CxbxKrnl/HLEDataBase/HLE_3911.rar b/src/CxbxKrnl/HLEDataBase/HLE_3911.rar deleted file mode 100644 index e03095dec2c2c40aae4731ab1356296e13918a0a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30746 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%0A>BX|pCZ11}RSpu7PNI-LkN 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