Merge pull request #1894 from PatrickvL/vertex_declaration_refactoring
Vertex declaration refactoring
This commit is contained in:
commit
213dd2f86f
|
@ -32,8 +32,12 @@ uniform float4 C[X_D3DVS_CONSTREG_COUNT] : register(c0);
|
|||
uniform float4 vRegisterDefaultValues[16] : register(c192);
|
||||
uniform float4 vRegisterDefaultFlagsPacked[4] : register(c208);
|
||||
|
||||
uniform float4 xboxViewportScale : register(c212);
|
||||
uniform float4 xboxViewportOffset : register(c213);
|
||||
uniform float4 xboxViewportScaleInverse : register(c212);
|
||||
uniform float4 xboxViewportOffset : register(c213);
|
||||
|
||||
uniform float4 xboxTextureScale[4] : register(c214);
|
||||
|
||||
uniform float4 xboxIsRHWTransformedPosition : register(c218);
|
||||
|
||||
// Overloaded casts, assuring all inputs are treated as float4
|
||||
float4 _tof4(float src) { return float4(src, src, src, src); }
|
||||
|
@ -149,17 +153,6 @@ float _dph(float4 src0, float4 src1)
|
|||
|
||||
// Xbox ILU Functions
|
||||
|
||||
// 2.14.1.10.6 RCP: Reciprocal
|
||||
#define x_rcp(dest, mask, src0) dest.mask = _ssss(_rcp(_scalar(src0))).mask
|
||||
float _rcp(float src)
|
||||
{
|
||||
#if 0 // TODO : Enable
|
||||
if (src == 1) return 1;
|
||||
if (src == 0) return 1.#INF;
|
||||
#endif
|
||||
return 1/ src;
|
||||
}
|
||||
|
||||
// 2.14.1.10.7 RSQ: Reciprocal Square Root
|
||||
#define x_rsq(dest, mask, src0) dest.mask = _ssss(_rsq(_scalar(src0))).mask
|
||||
float _rsq(float src)
|
||||
|
@ -251,6 +244,23 @@ float _rcc(float src)
|
|||
: clamp(r, -1.84467e+019f, -5.42101e-020f); // the IEEE 32-bit binary values 0xDF800000 and 0x9F800000
|
||||
}
|
||||
|
||||
// 2.14.1.10.6 RCP: Reciprocal
|
||||
#define x_rcp(dest, mask, src0) dest.mask = _ssss(_rcp(_scalar(src0))).mask
|
||||
float _rcp(float src)
|
||||
{
|
||||
// OpenGL/NVidia extension definition
|
||||
#if 0 // TODO : Enable?
|
||||
if (src == 1) return 1;
|
||||
if (src == 0) return 1.#INF;
|
||||
return 1 / src;
|
||||
#endif
|
||||
// Forward to Xbox clamped reciprocal
|
||||
// So we have defined behaviour with rcp(0)
|
||||
// This prevents issues with XYZRHW modes
|
||||
// where the w component may be 0
|
||||
return _rcc(src);
|
||||
}
|
||||
|
||||
float4 reverseScreenspaceTransform(float4 oPos)
|
||||
{
|
||||
// On Xbox, oPos should contain the vertex position in screenspace
|
||||
|
@ -261,13 +271,19 @@ float4 reverseScreenspaceTransform(float4 oPos)
|
|||
// mad oPos.xyz, r12, r1.x, c-37
|
||||
// where c-37 and c-38 are reserved transform values
|
||||
|
||||
if (xboxIsRHWTransformedPosition.x) {
|
||||
// Detect 0 w and avoid 0 division
|
||||
if (oPos.w == 0) oPos.w = 1; // if else doesn't seem to work here
|
||||
oPos.w = 1 / oPos.w; // flip rhw to w
|
||||
}
|
||||
|
||||
// oPos.w and xboxViewportScale.z might be VERY big when a D24 depth buffer is used
|
||||
// and multiplying oPos.xyz by oPos.w may cause precision issues.
|
||||
// Pre-divide them to help keep the values reasonably small.
|
||||
// Test case: Burnout 3
|
||||
float3 divisor = xboxViewportScale.xyz / oPos.w;
|
||||
|
||||
oPos.xyz -= xboxViewportOffset.xyz; // reverse offset
|
||||
oPos.xyz /= divisor; // reverse scale and perspective divide
|
||||
oPos.xyz *= oPos.w; // reverse perspective divide
|
||||
oPos.xyz *= xboxViewportScaleInverse.xyz; // reverse scale
|
||||
|
||||
return oPos;
|
||||
}
|
||||
|
@ -315,14 +331,15 @@ R"DELIMITER(
|
|||
xOut.oPos = reverseScreenspaceTransform(oPos);
|
||||
xOut.oD0 = saturate(oD0);
|
||||
xOut.oD1 = saturate(oD1);
|
||||
xOut.oFog = oFog.x;
|
||||
xOut.oFog = oFog.x; // Note : Xbox clamps fog in pixel shader
|
||||
xOut.oPts = oPts.x;
|
||||
xOut.oB0 = saturate(oB0);
|
||||
xOut.oB1 = saturate(oB1);
|
||||
xOut.oT0 = oT0;
|
||||
xOut.oT1 = oT1;
|
||||
xOut.oT2 = oT2;
|
||||
xOut.oT3 = oT3;
|
||||
// Scale textures (TODO : or should we apply this to the input register values?)
|
||||
xOut.oT0 = oT0 / xboxTextureScale[0];
|
||||
xOut.oT1 = oT1 / xboxTextureScale[1];
|
||||
xOut.oT2 = oT2 / xboxTextureScale[2];
|
||||
xOut.oT3 = oT3 / xboxTextureScale[3];
|
||||
|
||||
return xOut;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4195,3 +4195,64 @@ xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_SetPixelShaderConstant_4)
|
|||
hRet = D3D_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// ******************************************************************
|
||||
// * patch: D3DDevice_SelectVertexShaderDirect
|
||||
// ******************************************************************
|
||||
VOID WINAPI XTL::EMUPATCH(D3DDevice_SelectVertexShaderDirect)
|
||||
(
|
||||
X_VERTEXATTRIBUTEFORMAT *pVAF,
|
||||
DWORD Address
|
||||
)
|
||||
{
|
||||
LOG_FUNC_BEGIN
|
||||
LOG_FUNC_ARG(pVAF)
|
||||
LOG_FUNC_ARG(Address)
|
||||
LOG_FUNC_END;
|
||||
|
||||
CxbxImpl_SelectVertexShaderDirect(pVAF, Address);
|
||||
}
|
||||
|
||||
// ******************************************************************
|
||||
// * patch: D3DDevice_SetVertexShaderInputDirect
|
||||
// ******************************************************************
|
||||
VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexShaderInputDirect)
|
||||
(
|
||||
X_VERTEXATTRIBUTEFORMAT *pVAF,
|
||||
UINT StreamCount,
|
||||
X_STREAMINPUT *pStreamInputs
|
||||
)
|
||||
{
|
||||
LOG_FUNC_BEGIN
|
||||
LOG_FUNC_ARG(pVAF)
|
||||
LOG_FUNC_ARG(StreamCount)
|
||||
LOG_FUNC_ARG(pStreamInputs)
|
||||
LOG_FUNC_END;
|
||||
|
||||
// If pVAF is given, it's copied into a global Xbox VertexBuffer struct and
|
||||
// D3DDevice_SetVertexShaderInput is called with Handle set to that address, or-ed with 1 (X_D3DFVF_RESERVED0)
|
||||
// Otherwise, D3DDevice_SetVertexShaderInput is called with Handle 0.
|
||||
|
||||
LOG_UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
// ******************************************************************
|
||||
// * patch: D3DDevice_GetVertexShaderInput
|
||||
// ******************************************************************
|
||||
HRESULT WINAPI XTL::EMUPATCH(D3DDevice_GetVertexShaderInput)
|
||||
(
|
||||
DWORD *pHandle,
|
||||
UINT *pStreamCount,
|
||||
X_STREAMINPUT *pStreamInputs
|
||||
)
|
||||
{
|
||||
LOG_FUNC_BEGIN
|
||||
LOG_FUNC_ARG(pHandle)
|
||||
LOG_FUNC_ARG(pStreamCount)
|
||||
LOG_FUNC_ARG(pStreamInputs)
|
||||
LOG_FUNC_END;
|
||||
|
||||
LOG_UNIMPLEMENTED();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -63,6 +63,9 @@ extern uint8_t *ConvertD3DTextureToARGB(
|
|||
|
||||
void CxbxUpdateNativeD3DResources();
|
||||
|
||||
void CxbxImpl_SetRenderTarget(xbox::X_D3DSurface* pRenderTarget, xbox::X_D3DSurface* pNewZStencil);
|
||||
void CxbxImpl_SetViewPort(xbox::X_D3DVIEWPORT8* pViewport);
|
||||
|
||||
// initialize direct3d
|
||||
extern void EmuD3DInit();
|
||||
|
||||
|
@ -214,7 +217,7 @@ xbox::void_xt WINAPI EMUPATCH(D3DDevice_LoadVertexShader)
|
|||
);
|
||||
|
||||
xbox::void_xt __stdcall EMUPATCH(D3DDevice_LoadVertexShader_0)();
|
||||
xbox::void_xt WINAPI EMUPATCH(D3DDevice_LoadVertexShader_4)
|
||||
xbox::void_xt EMUPATCH(D3DDevice_LoadVertexShader_4)
|
||||
(
|
||||
dword_xt Address
|
||||
);
|
||||
|
@ -332,7 +335,7 @@ xbox::void_xt WINAPI EMUPATCH(D3DDevice_GetBackBuffer)
|
|||
// ******************************************************************
|
||||
xbox::void_xt WINAPI EMUPATCH(D3DDevice_SetViewport)
|
||||
(
|
||||
CONST X_D3DVIEWPORT8 *pViewport
|
||||
X_D3DVIEWPORT8 *pViewport
|
||||
);
|
||||
|
||||
// ******************************************************************
|
||||
|
@ -1602,15 +1605,6 @@ xbox::void_xt WINAPI EMUPATCH(D3DDevice_DeleteVertexShader)
|
|||
|
||||
xbox::void_xt WINAPI EMUPATCH(D3DDevice_DeleteVertexShader_0)();
|
||||
|
||||
// ******************************************************************
|
||||
// * patch: D3DDevice_SelectVertexShaderDirect
|
||||
// ******************************************************************
|
||||
xbox::void_xt WINAPI EMUPATCH(D3DDevice_SelectVertexShaderDirect)
|
||||
(
|
||||
X_VERTEXATTRIBUTEFORMAT *pVAF,
|
||||
dword_xt Address
|
||||
);
|
||||
|
||||
// ******************************************************************
|
||||
// * patch: D3DDevice_GetShaderConstantMode
|
||||
// ******************************************************************
|
||||
|
@ -1637,16 +1631,6 @@ xbox::void_xt WINAPI EMUPATCH(D3DDevice_GetVertexShaderConstant)
|
|||
dword_xt ConstantCount
|
||||
);
|
||||
|
||||
// ******************************************************************
|
||||
// * patch: D3DDevice_SetVertexShaderInputDirect
|
||||
// ******************************************************************
|
||||
xbox::void_xt WINAPI EMUPATCH(D3DDevice_SetVertexShaderInputDirect)
|
||||
(
|
||||
X_VERTEXATTRIBUTEFORMAT *pVAF,
|
||||
uint_xt StreamCount,
|
||||
X_STREAMINPUT *pStreamInputs
|
||||
);
|
||||
|
||||
// ******************************************************************
|
||||
// * patch: D3DDevice_GetVertexShaderInput
|
||||
// ******************************************************************
|
||||
|
@ -1658,7 +1642,7 @@ xbox::hresult_xt WINAPI EMUPATCH(D3DDevice_GetVertexShaderInput)
|
|||
);
|
||||
|
||||
// ******************************************************************
|
||||
// * patch: D3DDevice_GetVertexShaderInput
|
||||
// * patch: D3DDevice_SetVertexShaderInput
|
||||
// ******************************************************************
|
||||
xbox::void_xt WINAPI EMUPATCH(D3DDevice_SetVertexShaderInput)
|
||||
(
|
||||
|
|
|
@ -77,7 +77,7 @@ TextureStateInfo CxbxTextureStateInfo[] = {
|
|||
|
||||
bool XboxTextureStateConverter::Init(XboxRenderStateConverter* pState)
|
||||
{
|
||||
// Deferred states start at 0, this menas that D3DDeferredTextureState IS D3D__TextureState
|
||||
// Deferred states start at 0, this means that D3DDeferredTextureState IS D3D__TextureState
|
||||
// No further works is required to derive the offset
|
||||
if (g_SymbolAddresses.find("D3DDeferredTextureState") != g_SymbolAddresses.end()) {
|
||||
D3D__TextureState = (uint32_t*)g_SymbolAddresses["D3DDeferredTextureState"];
|
||||
|
@ -184,41 +184,89 @@ void XboxTextureStateConverter::Apply()
|
|||
switch (State) {
|
||||
// These types map 1:1 but have some unsupported values
|
||||
case xbox::X_D3DTSS_ADDRESSU: case xbox::X_D3DTSS_ADDRESSV: case xbox::X_D3DTSS_ADDRESSW:
|
||||
if (Value == xbox::X_D3DTADDRESS_CLAMPTOEDGE) {
|
||||
EmuLog(LOG_LEVEL::WARNING, "D3DTADDRESS_CLAMPTOEDGE is unsupported");
|
||||
// D3DTADDRESS_BORDER is the closest host match, CLAMPTOEDGE is identical
|
||||
// Except it has additional restrictions.
|
||||
Value = D3DTADDRESS_BORDER;
|
||||
break;
|
||||
switch (Value) {
|
||||
case 0: // Let's ignore zero (its no known X_D3DTADDRESS_ mode, but logging this seems useless)
|
||||
case xbox::X_D3DTADDRESS_WRAP: // = 1 = D3DTADDRESS_WRAP = 1,
|
||||
case xbox::X_D3DTADDRESS_MIRROR: // = 2 = D3DTADDRESS_MIRROR = 2,
|
||||
case xbox::X_D3DTADDRESS_CLAMP: // = 3 = D3DTADDRESS_CLAMP = 3,
|
||||
case xbox::X_D3DTADDRESS_BORDER: // = 4 = D3DTADDRESS_BORDER = 4,
|
||||
// These match host Direct3D 9 values, so no update necessary
|
||||
break;
|
||||
case xbox::X_D3DTADDRESS_CLAMPTOEDGE: // = 5
|
||||
LOG_TEST_CASE("X_D3DTADDRESS_CLAMPTOEDGE unsupported, falling back to D3DTADDRESS_BORDER");
|
||||
// D3DTADDRESS_BORDER is the closest host match, CLAMPTOEDGE is identical
|
||||
// Except it has additional restrictions.
|
||||
Value = D3DTADDRESS_BORDER;
|
||||
break;
|
||||
default:
|
||||
EmuLog(LOG_LEVEL::WARNING, "Unsupported X_D3DTSS_ADDRESS? value %x", Value);
|
||||
Value = D3DTADDRESS_WRAP;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case xbox::X_D3DTSS_MAGFILTER: case xbox::X_D3DTSS_MINFILTER: case xbox::X_D3DTSS_MIPFILTER:
|
||||
if (Value == xbox::X_D3DTEXF_QUINCUNX) {
|
||||
EmuLog(LOG_LEVEL::WARNING, "D3DTEXF_QUINCUNX is unsupported");
|
||||
// Fallback to D3DTEXF_ANISOTROPIC
|
||||
Value = D3DTEXF_ANISOTROPIC;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case xbox::X_D3DTSS_TEXCOORDINDEX:
|
||||
switch (Value) {
|
||||
case 0x00040000:
|
||||
// This value is TCI_OBJECT on Xbox,which is not supported by the host
|
||||
// In this case, we reset to 0.
|
||||
EmuLog(LOG_LEVEL::WARNING, "EmuD3DDevice_SetTextureState_TexCoordIndex: D3DTSS_TCI_OBJECT is unsupported", Value);
|
||||
Value = 0;
|
||||
case xbox::X_D3DTEXF_NONE: // = 0 = D3DTEXF_NONE = 0, // filtering disabled (valid for mip filter only)
|
||||
case xbox::X_D3DTEXF_POINT: // = 1 = D3DTEXF_POINT = 1, // nearest
|
||||
case xbox::X_D3DTEXF_LINEAR: // = 2 = D3DTEXF_LINEAR = 2, // linear interpolation
|
||||
case xbox::X_D3DTEXF_ANISOTROPIC: // = 3 = D3DTEXF_ANISOTROPIC = 3, // anisotropic
|
||||
// These match host Direct3D 9 values, so no update necessary
|
||||
break;
|
||||
case 0x00050000:
|
||||
// This value is TCI_SPHERE on Xbox, let's map it to D3DTSS_TCI_SPHEREMAP for the host
|
||||
Value = D3DTSS_TCI_SPHEREMAP;
|
||||
case xbox::X_D3DTEXF_QUINCUNX: // = 4; // quincunx kernel (Xbox extension), also known as "flat cubic"
|
||||
LOG_TEST_CASE("X_D3DTEXF_QUINCUNX unsupported, falling back to D3DTEXF_ANISOTROPIC");
|
||||
Value = D3DTEXF_ANISOTROPIC;
|
||||
break;
|
||||
case xbox::X_D3DTEXF_GAUSSIANCUBIC: // = 5 // Xbox extension, different cubic kernel
|
||||
// Direct3D 9 alternatives :
|
||||
// D3DTEXF_PYRAMIDALQUAD = 6, // 4-sample tent
|
||||
// D3DTEXF_GAUSSIANQUAD = 7, // 4-sample gaussian
|
||||
// D3DTEXF_CONVOLUTIONMONO = 8, // Convolution filter for monochrome textures
|
||||
LOG_TEST_CASE("X_D3DTEXF_QUINCUNX unsupported, falling back to D3DTEXF_GAUSSIANQUAD");
|
||||
Value = D3DTEXF_GAUSSIANQUAD;
|
||||
break;
|
||||
default:
|
||||
EmuLog(LOG_LEVEL::WARNING, "Unsupported X_D3DTSS_M??FILTER value %x", Value);
|
||||
Value = D3DTEXF_NONE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case xbox::X_D3DTSS_TEXCOORDINDEX: {
|
||||
int texCoordIndex = Value & 0x0000FFFF;
|
||||
if (texCoordIndex > 3) {
|
||||
LOG_TEST_CASE("TEXCOORDINDEX out of bounds, masking to lowest 2 bits");
|
||||
texCoordIndex = Value & 3;
|
||||
}
|
||||
switch (Value & 0xFFFF0000) {
|
||||
case X_D3DTSS_TCI_PASSTHRU: // = 0x00000000
|
||||
case X_D3DTSS_TCI_CAMERASPACENORMAL: // = 0x00010000
|
||||
case X_D3DTSS_TCI_CAMERASPACEPOSITION: // = 0x00020000
|
||||
case X_D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR: // = 0x00030000
|
||||
// These match host Direct3D 9 values, so no update necessary
|
||||
break;
|
||||
case X_D3DTSS_TCI_OBJECT: // = 0x00040000
|
||||
// Collides with host Direct3D 9 D3DTSS_TCI_SPHEREMAP
|
||||
// This value is not supported on host in Direct3D 9
|
||||
// It probably means "TexGen ObjectLinear", or '(untransformed) object space identity mapping'
|
||||
LOG_TEST_CASE("Xbox D3DTSS_TCI_OBJECT unsupported on host");
|
||||
// Test-case : Terrain XDK sample
|
||||
Value = texCoordIndex;
|
||||
break;
|
||||
case X_D3DTSS_TCI_SPHEREMAP: // = 0x00050000
|
||||
// Convert Xbox sphere mapping bit to host Direct3D 9 (which uses a different bit)
|
||||
Value = D3DTSS_TCI_SPHEREMAP | texCoordIndex;
|
||||
break;
|
||||
default:
|
||||
EmuLog(LOG_LEVEL::WARNING, "Unsupported X_D3DTSS_TEXCOORDINDEX value %x", Value);
|
||||
Value = texCoordIndex;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// These types require value remapping for all supported values
|
||||
case xbox::X_D3DTSS_COLOROP: case xbox::X_D3DTSS_ALPHAOP:
|
||||
Value = GetHostTextureOpValue(Value);
|
||||
break;
|
||||
// These types require no conversion, so we just pass through as-is
|
||||
// These types require no conversion, so we just pass through as-is
|
||||
case xbox::X_D3DTSS_COLORARG0: case xbox::X_D3DTSS_COLORARG1: case xbox::X_D3DTSS_COLORARG2:
|
||||
case xbox::X_D3DTSS_ALPHAARG0: case xbox::X_D3DTSS_ALPHAARG1: case xbox::X_D3DTSS_ALPHAARG2:
|
||||
case xbox::X_D3DTSS_RESULTARG: case xbox::X_D3DTSS_TEXTURETRANSFORMFLAGS:
|
||||
|
@ -273,3 +321,12 @@ void XboxTextureStateConverter::Apply()
|
|||
// no need to actually copy here, since it was handled in the loop above
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t XboxTextureStateConverter::Get(int textureStage, DWORD xboxState) {
|
||||
if (textureStage < 0 || textureStage > 3)
|
||||
CxbxKrnlCleanup("Requested texture stage was out of range: %d", textureStage);
|
||||
if (xboxState < xbox::X_D3DTSS_FIRST || xboxState > xbox::X_D3DTSS_LAST)
|
||||
CxbxKrnlCleanup("Requested texture state was out of range: %d", xboxState);
|
||||
|
||||
return D3D__TextureState[(textureStage * xbox::X_D3DTS_STAGESIZE) + xboxState];
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ class XboxTextureStateConverter
|
|||
public:
|
||||
bool Init(XboxRenderStateConverter* state);
|
||||
void Apply();
|
||||
uint32_t Get(int textureStage, DWORD xboxState);
|
||||
|
||||
private:
|
||||
void BuildTextureStateMappingTable();
|
||||
|
|
|
@ -220,44 +220,21 @@ extern ShaderType EmuGetShaderInfo(IntermediateVertexShader* pIntermediateShader
|
|||
return ShaderType::Compilable;
|
||||
}
|
||||
|
||||
// recompile xbox vertex shader function
|
||||
extern HRESULT EmuCompileShader
|
||||
(
|
||||
IntermediateVertexShader* pIntermediateShader,
|
||||
ID3DBlob** ppHostShader
|
||||
)
|
||||
HRESULT CompileHlsl(const std::string& hlsl, ID3DBlob** ppHostShader, const char* pSourceName)
|
||||
{
|
||||
// TODO include header in vertex shader
|
||||
//xbox::X_VSH_SHADER_HEADER* pXboxVertexShaderHeader = (xbox::X_VSH_SHADER_HEADER*)pXboxFunction;
|
||||
ID3DBlob* pErrors = nullptr;
|
||||
ID3DBlob* pErrorsCompatibility = nullptr;
|
||||
HRESULT hRet = 0;
|
||||
|
||||
// Include HLSL header and footer as raw strings :
|
||||
static std::string hlsl_template[2] = {
|
||||
#include "core\hle\D3D8\Direct3D9\CxbxVertexShaderTemplate.hlsl"
|
||||
};
|
||||
|
||||
auto hlsl_stream = std::stringstream();
|
||||
hlsl_stream << hlsl_template[0]; // Start with the HLSL template header
|
||||
assert(pIntermediateShader->Instructions.size() > 0);
|
||||
BuildShader(pIntermediateShader, hlsl_stream);
|
||||
|
||||
hlsl_stream << hlsl_template[1]; // Finish with the HLSL template footer
|
||||
std::string hlsl_str = hlsl_stream.str();
|
||||
|
||||
EmuLog(LOG_LEVEL::DEBUG, "--- HLSL conversion ---");
|
||||
EmuLog(LOG_LEVEL::DEBUG, DebugPrependLineNumbers(hlsl_str).c_str());
|
||||
EmuLog(LOG_LEVEL::DEBUG, "-----------------------");
|
||||
|
||||
|
||||
UINT flags1 = D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_AVOID_FLOW_CONTROL;
|
||||
|
||||
UINT flags1 = D3DCOMPILE_OPTIMIZATION_LEVEL3;
|
||||
hRet = D3DCompile(
|
||||
hlsl_str.c_str(),
|
||||
hlsl_str.length(),
|
||||
nullptr, // pSourceName
|
||||
hlsl.c_str(),
|
||||
hlsl.length(),
|
||||
pSourceName, // pSourceName
|
||||
nullptr, // pDefines
|
||||
nullptr, // pInclude // TODO precompile x_* HLSL functions?
|
||||
D3D_COMPILE_STANDARD_FILE_INCLUDE, // pInclude // TODO precompile x_* HLSL functions?
|
||||
"main", // shader entry poiint
|
||||
g_vs_model, // shader profile
|
||||
flags1, // flags1
|
||||
|
@ -266,25 +243,26 @@ extern HRESULT EmuCompileShader
|
|||
&pErrors // ppErrorMsgs out
|
||||
);
|
||||
if (FAILED(hRet)) {
|
||||
EmuLog(LOG_LEVEL::WARNING, "Shader compile failed. Recompiling in compatibility mode");
|
||||
// Attempt to retry in compatibility mode, this allows some vertex-state shaders to compile
|
||||
// Test Case: Spy vs Spy
|
||||
flags1 |= D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY;
|
||||
flags1 |= D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY | D3DCOMPILE_AVOID_FLOW_CONTROL;
|
||||
hRet = D3DCompile(
|
||||
hlsl_str.c_str(),
|
||||
hlsl_str.length(),
|
||||
nullptr, // pSourceName
|
||||
hlsl.c_str(),
|
||||
hlsl.length(),
|
||||
pSourceName, // pSourceName
|
||||
nullptr, // pDefines
|
||||
nullptr, // pInclude // TODO precompile x_* HLSL functions?
|
||||
D3D_COMPILE_STANDARD_FILE_INCLUDE, // pInclude // TODO precompile x_* HLSL functions?
|
||||
"main", // shader entry poiint
|
||||
g_vs_model, // shader profile
|
||||
flags1, // flags1
|
||||
0, // flags2
|
||||
ppHostShader, // out
|
||||
&pErrors // ppErrorMsgs out
|
||||
&pErrorsCompatibility // ppErrorMsgs out
|
||||
);
|
||||
|
||||
if (FAILED(hRet)) {
|
||||
LOG_TEST_CASE("Couldn't assemble recompiled vertex shader");
|
||||
LOG_TEST_CASE("Couldn't assemble vertex shader");
|
||||
//EmuLog(LOG_LEVEL::WARNING, "Couldn't assemble recompiled vertex shader");
|
||||
}
|
||||
}
|
||||
|
@ -296,6 +274,10 @@ extern HRESULT EmuCompileShader
|
|||
EmuLog(hlslErrorLogLevel, "%s", (char*)(pErrors->GetBufferPointer()));
|
||||
pErrors->Release();
|
||||
pErrors = nullptr;
|
||||
if (pErrorsCompatibility != nullptr) {
|
||||
pErrorsCompatibility->Release();
|
||||
pErrorsCompatibility = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_CHECK_ENABLED(LOG_LEVEL::DEBUG)
|
||||
|
@ -317,3 +299,156 @@ extern HRESULT EmuCompileShader
|
|||
|
||||
return hRet;
|
||||
}
|
||||
|
||||
// recompile xbox vertex shader function
|
||||
extern HRESULT EmuCompileShader
|
||||
(
|
||||
IntermediateVertexShader* pIntermediateShader,
|
||||
ID3DBlob** ppHostShader
|
||||
)
|
||||
{
|
||||
// Include HLSL header and footer as raw strings :
|
||||
static std::string hlsl_template[2] = {
|
||||
#include "core\hle\D3D8\Direct3D9\CxbxVertexShaderTemplate.hlsl"
|
||||
};
|
||||
|
||||
auto hlsl_stream = std::stringstream();
|
||||
hlsl_stream << hlsl_template[0]; // Start with the HLSL template header
|
||||
assert(pIntermediateShader->Instructions.size() > 0);
|
||||
BuildShader(pIntermediateShader, hlsl_stream);
|
||||
|
||||
hlsl_stream << hlsl_template[1]; // Finish with the HLSL template footer
|
||||
std::string hlsl_str = hlsl_stream.str();
|
||||
|
||||
EmuLog(LOG_LEVEL::DEBUG, "--- HLSL conversion ---");
|
||||
EmuLog(LOG_LEVEL::DEBUG, DebugPrependLineNumbers(hlsl_str).c_str());
|
||||
EmuLog(LOG_LEVEL::DEBUG, "-----------------------");
|
||||
|
||||
return CompileHlsl(hlsl_str, ppHostShader, "CxbxVertexShaderTemplate.hlsl");
|
||||
}
|
||||
|
||||
static ID3DBlob* pPassthroughShader = nullptr;
|
||||
|
||||
extern HRESULT EmuCompileXboxPassthrough(ID3DBlob** ppHostShader)
|
||||
{
|
||||
// TODO does this need to be thread safe?
|
||||
if (pPassthroughShader == nullptr) {
|
||||
auto hlsl =
|
||||
R"(
|
||||
// Xbox HLSL pretransformed vertex shader
|
||||
|
||||
// Default values for vertex registers, and whether to use them
|
||||
uniform float4 vRegisterDefaultValues[16] : register(c192);
|
||||
uniform float4 vRegisterDefaultFlagsPacked[4] : register(c208);
|
||||
|
||||
uniform float4 xboxViewportScaleInverse : register(c212);
|
||||
uniform float4 xboxViewportOffset : register(c213);
|
||||
|
||||
|
||||
uniform float4 xboxTextureScale[4] : register(c214);
|
||||
|
||||
uniform float4 xboxIsRHWTransformedPosition : register(c218);
|
||||
|
||||
struct VS_INPUT
|
||||
{
|
||||
float4 v[16] : TEXCOORD;
|
||||
};
|
||||
|
||||
// Output registers
|
||||
struct VS_OUTPUT
|
||||
{
|
||||
float4 oPos : POSITION; // Homogeneous clip space position
|
||||
float4 oD0 : COLOR0; // Primary color (front-facing)
|
||||
float4 oD1 : COLOR1; // Secondary color (front-facing)
|
||||
float oFog : FOG; // Fog coordinate
|
||||
float oPts : PSIZE; // Point size
|
||||
float4 oB0 : TEXCOORD4; // Back-facing primary color
|
||||
float4 oB1 : TEXCOORD5; // Back-facing secondary color
|
||||
float4 oT0 : TEXCOORD0; // Texture coordinate set 0
|
||||
float4 oT1 : TEXCOORD1; // Texture coordinate set 1
|
||||
float4 oT2 : TEXCOORD2; // Texture coordinate set 2
|
||||
float4 oT3 : TEXCOORD3; // Texture coordinate set 3
|
||||
};
|
||||
|
||||
float4 reverseScreenspaceTransform(float4 oPos)
|
||||
{
|
||||
// Scale screenspace coordinates (0 to viewport width/height) to -1 to +1 range
|
||||
|
||||
// On Xbox, oPos should contain the vertex position in screenspace
|
||||
// We need to reverse this transformation
|
||||
// Conventionally, each Xbox Vertex Shader includes instructions like this
|
||||
// mul oPos.xyz, r12, c-38
|
||||
// +rcc r1.x, r12.w
|
||||
// mad oPos.xyz, r12, r1.x, c-37
|
||||
// where c-37 and c-38 are reserved transform values
|
||||
|
||||
if (xboxIsRHWTransformedPosition.x) {
|
||||
// Detect 0 w and avoid 0 division
|
||||
if (oPos.w == 0) oPos.w = 1; // if else doesn't seem to work here
|
||||
oPos.w = 1 / oPos.w; // flip rhw to w
|
||||
}
|
||||
|
||||
oPos.xyz -= xboxViewportOffset.xyz; // reverse offset
|
||||
oPos.xyz *= oPos.w; // reverse perspective divide
|
||||
oPos.xyz *= xboxViewportScaleInverse.xyz; // reverse scale
|
||||
|
||||
return oPos;
|
||||
}
|
||||
|
||||
VS_OUTPUT main(const VS_INPUT xIn)
|
||||
{
|
||||
// Input registers
|
||||
float4 v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15;
|
||||
|
||||
// Unpack 16 flags from 4 float4 constant registers
|
||||
float vRegisterDefaultFlags[16] = (float[16])vRegisterDefaultFlagsPacked;
|
||||
|
||||
// Initialize input registers from the vertex buffer data
|
||||
// Or use the register's default value (which can be changed by the title)
|
||||
#define init_v(i) v##i = lerp(xIn.v[i], vRegisterDefaultValues[i], vRegisterDefaultFlags[i]);
|
||||
// Note : unroll manually instead of for-loop, because of the ## concatenation
|
||||
init_v( 0); init_v( 1); init_v( 2); init_v( 3);
|
||||
init_v( 4); init_v( 5); init_v( 6); init_v( 7);
|
||||
init_v( 8); init_v( 9); init_v(10); init_v(11);
|
||||
init_v(12); init_v(13); init_v(14); init_v(15);
|
||||
|
||||
// For passthrough, map output variables to their corresponding input registers
|
||||
float4 oPos = v0;
|
||||
float4 oD0 = v3;
|
||||
float4 oD1 = v4;
|
||||
float4 oFog = v5;
|
||||
float4 oPts = v6;
|
||||
float4 oB0 = v7;
|
||||
float4 oB1 = v8;
|
||||
float4 oT0 = v9;
|
||||
float4 oT1 = v10;
|
||||
float4 oT2 = v11;
|
||||
float4 oT3 = v12;
|
||||
|
||||
// Copy variables to output struct
|
||||
VS_OUTPUT xOut;
|
||||
|
||||
xOut.oPos = reverseScreenspaceTransform(oPos);
|
||||
xOut.oD0 = saturate(oD0);
|
||||
xOut.oD1 = saturate(oD1);
|
||||
xOut.oFog = oFog.x; // Note : Xbox clamps fog in pixel shader
|
||||
xOut.oPts = oPts.x;
|
||||
xOut.oB0 = saturate(oB0);
|
||||
xOut.oB1 = saturate(oB1);
|
||||
// Scale textures (TODO : or should we apply this to the input register values?)
|
||||
xOut.oT0 = oT0 / xboxTextureScale[0];
|
||||
xOut.oT1 = oT1 / xboxTextureScale[1];
|
||||
xOut.oT2 = oT2 / xboxTextureScale[2];
|
||||
xOut.oT3 = oT3 / xboxTextureScale[3];
|
||||
|
||||
return xOut;
|
||||
}
|
||||
)";
|
||||
|
||||
CompileHlsl(hlsl, &pPassthroughShader, "passthrough.hlsl");
|
||||
}
|
||||
|
||||
*ppHostShader = pPassthroughShader;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -22,4 +22,6 @@ extern HRESULT EmuCompileShader
|
|||
ID3DBlob** ppHostShader
|
||||
);
|
||||
|
||||
extern HRESULT EmuCompileXboxPassthrough(ID3DBlob** ppHostShader);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -43,7 +43,7 @@ ID3DBlob* AsyncCreateVertexShader(IntermediateVertexShader intermediateShader, S
|
|||
|
||||
// Create a new shader
|
||||
// If the shader was already created, just increase its reference count
|
||||
ShaderKey VertexShaderSource::CreateShader(const DWORD* pXboxFunction, DWORD *pXboxFunctionSize) {
|
||||
ShaderKey VertexShaderSource::CreateShader(const xbox::dword_xt* pXboxFunction, DWORD *pXboxFunctionSize) {
|
||||
IntermediateVertexShader intermediateShader;
|
||||
|
||||
// Parse into intermediate format
|
||||
|
|
|
@ -11,7 +11,7 @@ typedef uint64_t ShaderKey;
|
|||
class VertexShaderSource {
|
||||
|
||||
public:
|
||||
ShaderKey CreateShader(const DWORD* pXboxFunction, DWORD* pXboxFunctionSize);
|
||||
ShaderKey CreateShader(const xbox::dword_xt* pXboxFunction, DWORD* pXboxFunctionSize);
|
||||
IDirect3DVertexShader *GetShader(ShaderKey key);
|
||||
void ReleaseShader(ShaderKey key);
|
||||
|
||||
|
|
|
@ -929,7 +929,7 @@ static const FormatInfo FormatInfos[] = {
|
|||
/* 0x33 X_D3DFMT_V16U16 */ { 32, Swzzld, NoCmpnts, D3DFMT_V16U16 },
|
||||
/* 0x34 undefined */ {},
|
||||
/* 0x35 X_D3DFMT_LIN_L16 */ { 16, Linear, _____L16, D3DFMT_L16 },
|
||||
/* 0x36 X_D3DFMT_LIN_V16U16 */ { 32, Linear, NoCmpnts, D3DFMT_V16U16 }, // Note : Seems ununsed on Xbox
|
||||
/* 0x36 X_D3DFMT_LIN_V16U16 */ { 32, Linear, NoCmpnts, D3DFMT_V16U16 }, // Note : Seems unused on Xbox
|
||||
/* 0x37 X_D3DFMT_LIN_L6V5U5 */ { 16, Linear, __R6G5B5, D3DFMT_L6V5U5 }, // Alias : X_D3DFMT_LIN_R6G5B5
|
||||
/* 0x38 X_D3DFMT_R5G5B5A1 */ { 16, Swzzld, R5G5B5A1, D3DFMT_A1R5G5B5 , Texture, "X_D3DFMT_R5G5B5A1 -> D3DFMT_A1R5G5B5" },
|
||||
/* 0x39 X_D3DFMT_R4G4B4A4 */ { 16, Swzzld, R4G4B4A4, D3DFMT_A4R4G4B4 , Texture, "X_D3DFMT_R4G4B4A4 -> D3DFMT_A4R4G4B4" },
|
||||
|
|
|
@ -1020,9 +1020,22 @@ typedef DWORD X_VERTEXSHADERCONSTANTMODE;
|
|||
// Special Registers, used to pass additional information to the shaders
|
||||
// TODO co-locate shader workaround constants with shader code
|
||||
#define CXBX_D3DVS_CONSTREG_VREGDEFAULTS_BASE (X_D3DVS_CONSTREG_COUNT)
|
||||
#define CXBX_D3DVS_CONSTREG_VREGDEFAULTS_FLAG_BASE (CXBX_D3DVS_CONSTREG_VREGDEFAULTS_BASE + 16)
|
||||
#define CXBX_D3DVS_VIEWPORT_SCALE_MIRROR (CXBX_D3DVS_CONSTREG_VREGDEFAULTS_FLAG_BASE + 4)
|
||||
#define CXBX_D3DVS_VIEWPORT_OFFSET_MIRROR (CXBX_D3DVS_VIEWPORT_SCALE_MIRROR + 1)
|
||||
#define CXBX_D3DVS_CONSTREG_VREGDEFAULTS_SIZE 16
|
||||
|
||||
#define CXBX_D3DVS_CONSTREG_VREGDEFAULTS_FLAG_BASE (CXBX_D3DVS_CONSTREG_VREGDEFAULTS_BASE + CXBX_D3DVS_CONSTREG_VREGDEFAULTS_SIZE)
|
||||
#define CXBX_D3DVS_CONSTREG_VREGDEFAULTS_FLAG_SIZE 4
|
||||
|
||||
#define CXBX_D3DVS_VIEWPORT_SCALE_INVERSE_BASE (CXBX_D3DVS_CONSTREG_VREGDEFAULTS_FLAG_BASE + CXBX_D3DVS_CONSTREG_VREGDEFAULTS_FLAG_SIZE)
|
||||
#define CXBX_D3DVS_VIEWPORT_SCALE_INVERSE_SIZE 1
|
||||
|
||||
#define CXBX_D3DVS_VIEWPORT_OFFSET_MIRROR_BASE (CXBX_D3DVS_VIEWPORT_SCALE_INVERSE_BASE + CXBX_D3DVS_VIEWPORT_SCALE_INVERSE_SIZE)
|
||||
#define CXBX_D3DVS_VIEWPORT_OFFSET_MIRROR_SIZE 1
|
||||
|
||||
#define CXBX_D3DVS_TEXTURES_SCALE_BASE (CXBX_D3DVS_VIEWPORT_OFFSET_MIRROR_BASE + CXBX_D3DVS_VIEWPORT_OFFSET_MIRROR_SIZE)
|
||||
#define CXBX_D3DVS_TEXTURES_SCALE_SIZE 4
|
||||
|
||||
#define CXBX_D3DVS_IS_RHW_TRANSFORMED_POSITION_BASE (CXBX_D3DVS_TEXTURES_SCALE_BASE + CXBX_D3DVS_TEXTURES_SCALE_SIZE)
|
||||
#define CXBX_D3DVS_IS_RHW_TRANSFORMED_POSITION_SIZE 1
|
||||
|
||||
#define X_D3DSCM_RESERVED_CONSTANT_SCALE_CORRECTED (X_D3DSCM_RESERVED_CONSTANT_SCALE + X_D3DSCM_CORRECTION)
|
||||
#define X_D3DSCM_RESERVED_CONSTANT_OFFSET_CORRECTED (X_D3DSCM_RESERVED_CONSTANT_OFFSET + X_D3DSCM_CORRECTION)
|
||||
|
@ -1039,14 +1052,16 @@ typedef DWORD X_VERTEXSHADERCONSTANTMODE;
|
|||
#define X_VST_STATE 3
|
||||
|
||||
// Xbox vertex shader counts
|
||||
#define X_VSH_MAX_ATTRIBUTES 16
|
||||
#define X_VSH_MAX_STREAMS 16
|
||||
#define X_VSH_MAX_INSTRUCTION_COUNT 136 // The maximum Xbox shader instruction count
|
||||
#define X_VSH_MAX_ATTRIBUTES 16
|
||||
#define X_VSH_MAX_STREAMS 16
|
||||
#define X_VSH_MAX_INSTRUCTION_COUNT 136 // The maximum Xbox shader instruction count
|
||||
#define X_VSH_INSTRUCTION_SIZE 4
|
||||
#define X_VSH_INSTRUCTION_SIZE_BYTES (X_VSH_INSTRUCTION_SIZE * sizeof(DWORD))
|
||||
|
||||
// Xbox Vertex Shader versions
|
||||
#define VERSION_XVS 0x2078 // 'x ' Xbox vertex shader
|
||||
#define VERSION_XVSS 0x7378 // 'xs' Xbox vertex state shader
|
||||
#define VERSION_XVSW 0x7778 // 'xw' Xbox vertex read/write shader
|
||||
#define VERSION_XVS 0x2078 // 'x ' Xbox vertex shader. Corresponds to X_VST_NORMAL
|
||||
#define VERSION_XVSS 0x7378 // 'xs' Xbox vertex state shader. Corresponds to X_VST_STATE
|
||||
#define VERSION_XVSW 0x7778 // 'xw' Xbox vertex read/write shader. Corresponds to X_VST_READWRITE
|
||||
|
||||
/// nv2a microcode header
|
||||
typedef struct
|
||||
|
@ -1056,22 +1071,30 @@ typedef struct
|
|||
}
|
||||
X_VSH_SHADER_HEADER;
|
||||
|
||||
#define X_VSH_INSTRUCTION_SIZE 4
|
||||
#define X_VSH_INSTRUCTION_SIZE_BYTES (X_VSH_INSTRUCTION_SIZE * sizeof(DWORD))
|
||||
|
||||
// ******************************************************************
|
||||
// * X_VERTEXSHADERINPUT
|
||||
// ******************************************************************
|
||||
typedef struct _X_VERTEXSHADERINPUT
|
||||
{
|
||||
DWORD IndexOfStream;
|
||||
DWORD StreamIndex;
|
||||
DWORD Offset;
|
||||
DWORD Format;
|
||||
BYTE TesselationType;
|
||||
BYTE TesselationSource;
|
||||
BYTE TessellationType;
|
||||
BYTE TessellationSource;
|
||||
BYTE Padding0;
|
||||
BYTE Padding1;
|
||||
}
|
||||
X_VERTEXSHADERINPUT;
|
||||
|
||||
typedef struct {
|
||||
DWORD StreamIndex;
|
||||
DWORD Offset;
|
||||
DWORD SizeAndType;
|
||||
BYTE Flags;
|
||||
BYTE Source;
|
||||
}
|
||||
X_VertexShaderSlot;
|
||||
|
||||
// ******************************************************************
|
||||
// * X_VERTEXATTRIBUTEFORMAT
|
||||
// ******************************************************************
|
||||
|
@ -1092,34 +1115,64 @@ typedef struct _X_STREAMINPUT
|
|||
UINT Offset;
|
||||
} X_STREAMINPUT;
|
||||
|
||||
struct X_D3DVertexShader3948
|
||||
{
|
||||
#if 0
|
||||
DWORD Signature; // Note : Debug XBE's have a 'Vshd' DWORD signature prefix
|
||||
#endif
|
||||
DWORD RefCount; // Based on the observation this member is set to 1 in D3DDevice_CreateVertexShader and decreased in D3DDevice_DeleteVertexShader
|
||||
DWORD Flags; // Seems to contain at solely the four X_D3DUSAGE_PERSISTENT* flags
|
||||
DWORD MaxSlot;
|
||||
DWORD TextureCount;
|
||||
DWORD ProgramSize;
|
||||
DWORD ProgramAndConstantsDwords; // Sum of ProgramSize + constant count, expressed in instruction slots, taking 4 DWORD's per slot (see X_VSH_INSTRUCTION_SIZE)
|
||||
DWORD Dimensionality[4] ; // Guesswork, since all 4 bytes (for all 4 textures) are most often set to 0 (or 2 when a texture isn't used) and 1, 3 and 4 also occur (and nothing else)
|
||||
X_VERTEXATTRIBUTEFORMAT VertexAttribute;
|
||||
X_VertexShaderSlot Slot[4]; // Four more (for a total of 20)
|
||||
DWORD ProgramAndConstants[1 /*declare more for debugging purposes */+ X_VSH_MAX_INSTRUCTION_COUNT]; // The binary function data and constants (contents continues futher outside this struct, up to ProgramAndConstantsDwords * 4 (=X_VSH_INSTRUCTION_SIZE) DWORD's)
|
||||
};
|
||||
|
||||
struct X_D3DVertexShader
|
||||
{
|
||||
// Note : Debug XBE's have a 'Vshd' DWORD signature prefixing this!
|
||||
#if 0
|
||||
DWORD Signature; // Note : Debug XBE's have a 'Vshd' DWORD signature prefix
|
||||
#endif
|
||||
DWORD RefCount; // Based on the observation this member is set to 1 in D3DDevice_CreateVertexShader and decreased in D3DDevice_DeleteVertexShader
|
||||
DWORD Flags;
|
||||
DWORD FunctionSize; // ?Also known as ProgramSize?
|
||||
DWORD TotalSize; // seems to include both the function and ?constants?
|
||||
DWORD NumberOfDimensionsPerTexture; // Guesswork, since all 4 bytes (for all 4 textures) are most often set to 0 (or 2 when a texture isn't used) and 1, 3 and 4 also occur (and nothing else)
|
||||
DWORD Flags; // Contains X_VERTEXSHADER_FLAG_* bits
|
||||
DWORD ProgramSize;
|
||||
DWORD ProgramAndConstantsDwords; // Sum of ProgramSize + constant count, expressed in instruction slots, taking 4 DWORD's per slot (see X_VSH_INSTRUCTION_SIZE)
|
||||
BYTE Dimensionality[4] ; // Guesswork, since all 4 bytes (for all 4 textures) are most often set to 0 (or 2 when a texture isn't used) and 1, 3 and 4 also occur (and nothing else)
|
||||
X_VERTEXATTRIBUTEFORMAT VertexAttribute;
|
||||
DWORD FunctionData[X_VSH_MAX_INSTRUCTION_COUNT]; // probably the binary function data and ?constants? (data continues futher outside this struct, up to TotalSize DWORD's)
|
||||
DWORD ProgramAndConstants[X_VSH_MAX_INSTRUCTION_COUNT]; // The binary function data and constants (contents continues futher outside this struct, up to ProgramAndConstantsDwords * 4 (=X_VSH_INSTRUCTION_SIZE) DWORD's)
|
||||
};
|
||||
|
||||
// X_D3DVertexShader.Flags values :
|
||||
#define X_VERTEXSHADER_FLAG_WRITE (1 << 0) // = 0x0001 // Set for Xbox ShaderType != X_VST_NORMAL
|
||||
#define X_VERTEXSHADER_FLAG_PASSTHROUGH (1 << 1) // = 0x0002
|
||||
#define X_VERTEXSHADER_FLAG_UNKNOWN (1 << 2) // = 0x0004 // Test case: Amped
|
||||
#define X_VERTEXSHADER_FLAG_STATE (1 << 3) // = 0x0008 // Set for Xbox ShaderType == X_VST_STATE
|
||||
#define X_VERTEXSHADER_FLAG_PROGRAM (1 << 4) // = 0x0010 // Set when X_D3DVertexShader was created with assigned function data
|
||||
#define X_VERTEXSHADER_FLAG_HASDIFFUSE (1 << 10) // = 0x0400 Corresponds to X_D3DUSAGE_PERSISTENTDIFFUSE
|
||||
#define X_VERTEXSHADER_FLAG_HASSPECULAR (1 << 11) // = 0x0800 Corresponds to X_D3DUSAGE_PERSISTENTSPECULAR
|
||||
#define X_VERTEXSHADER_FLAG_HASBACKDIFFUSE (1 << 12) // = 0x1000 Corresponds to X_D3DUSAGE_PERSISTENTBACKDIFFUSE
|
||||
#define X_VERTEXSHADER_FLAG_HASBACKSPECULAR (1 << 13) // = 0x2000 Corresponds to X_D3DUSAGE_PERSISTENTBACKSPECULAR
|
||||
|
||||
// vertex shader input registers for fixed function vertex shader
|
||||
|
||||
// Name Register number D3DFVF
|
||||
const int X_D3DVSDE_POSITION = 0; // Corresponds to D3DFVF_XYZ
|
||||
const int X_D3DVSDE_BLENDWEIGHT = 1; // Corresponds to D3DFVF_XYZRHW
|
||||
const int X_D3DVSDE_NORMAL = 2; // Corresponds to D3DFVF_NORMAL
|
||||
const int X_D3DVSDE_DIFFUSE = 3; // Corresponds to D3DFVF_DIFFUSE
|
||||
const int X_D3DVSDE_SPECULAR = 4; // Corresponds to D3DFVF_SPECULAR
|
||||
const int X_D3DVSDE_POSITION = 0; // Corresponds to X_D3DFVF_XYZ
|
||||
const int X_D3DVSDE_BLENDWEIGHT = 1; // Corresponds to X_D3DFVF_XYZB1? (was X_D3DFVF_XYZRHW?)
|
||||
const int X_D3DVSDE_NORMAL = 2; // Corresponds to X_D3DFVF_NORMAL
|
||||
const int X_D3DVSDE_DIFFUSE = 3; // Corresponds to X_D3DFVF_DIFFUSE
|
||||
const int X_D3DVSDE_SPECULAR = 4; // Corresponds to X_D3DFVF_SPECULAR
|
||||
const int X_D3DVSDE_FOG = 5; // Xbox extension
|
||||
const int X_D3DVSDE_POINTSIZE = 6; // Dxbx addition
|
||||
const int X_D3DVSDE_BACKDIFFUSE = 7; // Xbox extension
|
||||
const int X_D3DVSDE_BACKSPECULAR = 8; // Xbox extension
|
||||
const int X_D3DVSDE_TEXCOORD0 = 9; // Corresponds to D3DFVF_TEX1 (not D3DFVF_TEX0, which means no textures are present)
|
||||
const int X_D3DVSDE_TEXCOORD1 = 10; // Corresponds to D3DFVF_TEX2
|
||||
const int X_D3DVSDE_TEXCOORD2 = 11; // Corresponds to D3DFVF_TEX3
|
||||
const int X_D3DVSDE_TEXCOORD3 = 12; // Corresponds to D3DFVF_TEX4
|
||||
const int X_D3DVSDE_TEXCOORD0 = 9; // Corresponds to X_D3DFVF_TEX1 (not X_D3DFVF_TEX0, which means no textures are present)
|
||||
const int X_D3DVSDE_TEXCOORD1 = 10; // Corresponds to X_D3DFVF_TEX2
|
||||
const int X_D3DVSDE_TEXCOORD2 = 11; // Corresponds to X_D3DFVF_TEX3
|
||||
const int X_D3DVSDE_TEXCOORD3 = 12; // Corresponds to X_D3DFVF_TEX4
|
||||
const int X_D3DVSDE_VERTEX = 0xFFFFFFFF; // Xbox extension for Begin/End drawing (data is a D3DVSDT_FLOAT4)
|
||||
|
||||
//typedef X_D3DVSDE = X_D3DVSDE_POSITION..High(DWORD)-2; // Unique declaration to make overloads possible;
|
||||
|
@ -1233,12 +1286,22 @@ typedef enum _X_D3DVSD_TOKENTYPE
|
|||
#define X_D3DFVF_TEXTUREFORMAT2 0x000
|
||||
#define X_D3DFVF_TEXTUREFORMAT3 0x001
|
||||
#define X_D3DFVF_TEXTUREFORMAT4 0x002
|
||||
|
||||
#define X_D3DFVF_TEXCOORDSIZE_SHIFT(Index) ((Index) * 2 + 16)
|
||||
#define X_D3DFVF_TEXCOORDSIZE1(Index) (X_D3DFVF_TEXTUREFORMAT1 << (Index * 2 + 16))
|
||||
#define X_D3DFVF_TEXCOORDSIZE2(Index) (X_D3DFVF_TEXTUREFORMAT2)
|
||||
#define X_D3DFVF_TEXCOORDSIZE3(Index) (X_D3DFVF_TEXTUREFORMAT3 << (Index * 2 + 16))
|
||||
#define X_D3DFVF_TEXCOORDSIZE4(Index) (X_D3DFVF_TEXTUREFORMAT4 << (Index * 2 + 16))
|
||||
|
||||
// Values, used with D3DTSS_TEXCOORDINDEX, to specify that the vertex data (position
|
||||
// and normal in the camera space) should be taken as texture coordinates.
|
||||
// Low 16 bits are used to specify texture coordinate index, to take the WRAP mode from.
|
||||
#define X_D3DTSS_TCI_PASSTHRU 0x00000000
|
||||
#define X_D3DTSS_TCI_CAMERASPACENORMAL 0x00010000
|
||||
#define X_D3DTSS_TCI_CAMERASPACEPOSITION 0x00020000
|
||||
#define X_D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR 0x00030000
|
||||
#define X_D3DTSS_TCI_OBJECT 0x00040000 // Warning! Collides with host Direct3D 9 D3DTSS_TCI_SPHEREMAP
|
||||
#define X_D3DTSS_TCI_SPHEREMAP 0x00050000
|
||||
|
||||
typedef DWORD NV2AMETHOD;
|
||||
|
||||
//
|
||||
|
|
|
@ -66,8 +66,9 @@
|
|||
#include <process.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include "Direct3D9\RenderStates.h"
|
||||
extern XboxRenderStateConverter XboxRenderStates;
|
||||
#include "Direct3D9\RenderStates.h" // For XboxRenderStateConverter
|
||||
|
||||
extern XboxRenderStateConverter XboxRenderStates; // Declared in Direct3D9.cpp
|
||||
|
||||
#define DbgPshPrintf \
|
||||
LOG_CHECK_ENABLED(LOG_LEVEL::DEBUG) \
|
||||
|
|
|
@ -40,82 +40,12 @@
|
|||
#include "Logging.h"
|
||||
|
||||
// TODO: Find somewhere to put this that doesn't conflict with xbox::
|
||||
extern void EmuUpdateActiveTextureStages();
|
||||
extern void CxbxUpdateHostTextures();
|
||||
|
||||
const char *NV2AMethodToString(DWORD dwMethod); // forward
|
||||
|
||||
static void DbgDumpMesh(WORD *pIndexData, DWORD dwCount);
|
||||
|
||||
// Determine the size (in number of floating point texture coordinates) of the texture format (indexed 0 .. 3).
|
||||
// This is the reverse of the D3DFVF_TEXCOORDSIZE[0..3] macros.
|
||||
int DxbxFVF_GetNumberOfTextureCoordinates(DWORD dwFVF, int aTextureIndex)
|
||||
{
|
||||
// See D3DFVF_TEXCOORDSIZE1()
|
||||
switch ((dwFVF >> ((aTextureIndex * 2) + 16)) & 3) {
|
||||
case D3DFVF_TEXTUREFORMAT1: return 1; // One floating point value
|
||||
case D3DFVF_TEXTUREFORMAT2: return 2; // Two floating point values
|
||||
case D3DFVF_TEXTUREFORMAT3: return 3; // Three floating point values
|
||||
case D3DFVF_TEXTUREFORMAT4: return 4; // Four floating point values
|
||||
default:
|
||||
//assert(false || "DxbxFVF_GetNumberOfTextureCoordinates : Unhandled case");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Dxbx Note: This code appeared in EmuExecutePushBufferRaw and occured
|
||||
// in EmuFlushIVB too, so it's generalize in this single implementation.
|
||||
UINT DxbxFVFToVertexSizeInBytes(DWORD dwFVF, BOOL bIncludeTextures)
|
||||
{
|
||||
/*
|
||||
X_D3DFVF_POSITION_MASK = $00E; // Dec /2 #fl
|
||||
|
||||
X_D3DFVF_XYZ = $002; // 2 > 1 > 3
|
||||
X_D3DFVF_XYZRHW = $004; // 4 > 2 > 4
|
||||
X_D3DFVF_XYZB1 = $006; // 6 > 3 > 4
|
||||
X_D3DFVF_XYZB2 = $008; // 8 > 4 > 5
|
||||
X_D3DFVF_XYZB3 = $00a; // 10 > 5 > 6
|
||||
X_D3DFVF_XYZB4 = $00c; // 12 > 6 > 7
|
||||
*/
|
||||
// Divide the D3DFVF by two, this gives almost the number of floats needed for the format :
|
||||
UINT Result = (dwFVF & D3DFVF_POSITION_MASK) >> 1;
|
||||
if (Result >= (D3DFVF_XYZB1 >> 1)) {
|
||||
// Any format from D3DFVF_XYZB1 and above need 1 extra float :
|
||||
Result++;
|
||||
}
|
||||
else {
|
||||
// The other formats (XYZ and XYZRHW) need 2 extra floats :
|
||||
Result += 2;
|
||||
}
|
||||
|
||||
// Express the size in bytes, instead of floats :
|
||||
Result *= sizeof(FLOAT);
|
||||
|
||||
// D3DFVF_NORMAL cannot be combined with D3DFVF_XYZRHW :
|
||||
if ((dwFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZRHW) {
|
||||
if (dwFVF & D3DFVF_NORMAL) {
|
||||
Result += sizeof(FLOAT) * 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (dwFVF & D3DFVF_DIFFUSE) {
|
||||
Result += sizeof(D3DCOLOR);
|
||||
}
|
||||
|
||||
if (dwFVF & D3DFVF_SPECULAR) {
|
||||
Result += sizeof(D3DCOLOR);
|
||||
}
|
||||
|
||||
if (bIncludeTextures) {
|
||||
int NrTextures = ((dwFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT);
|
||||
while (NrTextures > 0) {
|
||||
NrTextures--;
|
||||
Result += DxbxFVF_GetNumberOfTextureCoordinates(dwFVF, NrTextures) * sizeof(FLOAT);
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
void EmuExecutePushBuffer
|
||||
(
|
||||
xbox::X_D3DPushBuffer *pPushBuffer,
|
||||
|
@ -162,11 +92,11 @@ void EmuExecutePushBuffer
|
|||
return;
|
||||
}
|
||||
|
||||
DWORD CxbxGetStrideFromVertexShaderHandle(DWORD dwVertexShader)
|
||||
DWORD CxbxGetStrideFromVertexDeclaration(CxbxVertexDeclaration* pCxbxVertexDeclaration)
|
||||
{
|
||||
DWORD Stride = 0;
|
||||
|
||||
if (VshHandleIsVertexShader(dwVertexShader)) {
|
||||
if (pCxbxVertexDeclaration) {
|
||||
// Test-case : Crash 'n' Burn [45530014]
|
||||
// Test-case : CrimsonSea [4B4F0002]
|
||||
// Test-case : Freedom Fighters
|
||||
|
@ -178,24 +108,16 @@ DWORD CxbxGetStrideFromVertexShaderHandle(DWORD dwVertexShader)
|
|||
// Test-case : SpyHunter 2 [4D57001B]
|
||||
//LOG_TEST_CASE("Non-FVF Vertex Shaders not yet (completely) supported for PushBuffer emulation!");
|
||||
|
||||
CxbxVertexShader *pCxbxVertexShader = GetCxbxVertexShader(dwVertexShader);
|
||||
if (pCxbxVertexShader) {
|
||||
if (pCxbxVertexShader->Declaration.NumberOfVertexStreams == 1) {
|
||||
// Note : This assumes that the only stream in use will be stream zero :
|
||||
Stride = pCxbxVertexShader->Declaration.VertexStreams[0].HostVertexStride;
|
||||
}
|
||||
else {
|
||||
LOG_TEST_CASE("Non-FVF Vertex Shaders with multiple streams not supported for PushBuffer emulation!");
|
||||
}
|
||||
if (pCxbxVertexDeclaration->NumberOfVertexStreams == 1) {
|
||||
// Note : This assumes that the only stream in use will be stream zero :
|
||||
Stride = pCxbxVertexDeclaration->VertexStreams[0].HostVertexStride;
|
||||
}
|
||||
else {
|
||||
LOG_TEST_CASE("Non-FVF Vertex Shaders with multiple streams not supported for PushBuffer emulation!");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (VshHandleIsFVF(dwVertexShader)) {
|
||||
Stride = DxbxFVFToVertexSizeInBytes(dwVertexShader, /*bIncludeTextures=*/true);
|
||||
}
|
||||
else {
|
||||
LOG_TEST_CASE("Invalid Vertex Shader not supported for PushBuffer emulation!");
|
||||
}
|
||||
LOG_TEST_CASE("Missing Vertex Declaration not supported for PushBuffer emulation!");
|
||||
}
|
||||
|
||||
return Stride;
|
||||
|
@ -233,7 +155,7 @@ void HLE_draw_inline_array(NV2AState *d)
|
|||
}
|
||||
// render vertices
|
||||
else {
|
||||
DWORD dwVertexStride = CxbxGetStrideFromVertexShaderHandle(g_Xbox_VertexShader_Handle);
|
||||
DWORD dwVertexStride = CxbxGetStrideFromVertexDeclaration(CxbxGetVertexDeclaration());
|
||||
if (dwVertexStride > 0) {
|
||||
UINT VertexCount = (pg->inline_array_length * sizeof(DWORD)) / dwVertexStride;
|
||||
CxbxDrawContext DrawContext = {};
|
||||
|
@ -252,16 +174,14 @@ void HLE_draw_inline_elements(NV2AState *d)
|
|||
{
|
||||
PGRAPHState *pg = &d->pgraph;
|
||||
|
||||
if (IsValidCurrentShader()) {
|
||||
unsigned int uiIndexCount = pg->inline_elements_length;
|
||||
CxbxDrawContext DrawContext = {};
|
||||
unsigned int uiIndexCount = pg->inline_elements_length;
|
||||
CxbxDrawContext DrawContext = {};
|
||||
|
||||
DrawContext.XboxPrimitiveType = (xbox::X_D3DPRIMITIVETYPE)pg->primitive_mode;
|
||||
DrawContext.dwVertexCount = uiIndexCount;
|
||||
DrawContext.pXboxIndexData = d->pgraph.inline_elements;
|
||||
DrawContext.dwVertexCount = uiIndexCount;
|
||||
DrawContext.pXboxIndexData = d->pgraph.inline_elements;
|
||||
|
||||
CxbxDrawIndexed(DrawContext);
|
||||
}
|
||||
CxbxDrawIndexed(DrawContext);
|
||||
}
|
||||
|
||||
DWORD ABGR_to_ARGB(const uint32_t color)
|
||||
|
@ -357,32 +277,38 @@ uint32_t HLE_read_NV2A_pgraph_register(const int reg)
|
|||
return pg->regs[reg];
|
||||
}
|
||||
|
||||
void HLE_write_NV2A_vertex_attribute_slot(unsigned slot, uint32_t parameter)
|
||||
{
|
||||
// Write value to LLE NV2A device
|
||||
pgraph_handle_method(g_NV2A->GetDeviceState(),
|
||||
/*subchannel=*/0,
|
||||
/*method=*/NV097_SET_VERTEX_DATA4UB + (4 * slot),
|
||||
parameter);
|
||||
}
|
||||
|
||||
uint32_t HLE_read_NV2A_vertex_attribute_slot(unsigned slot)
|
||||
float *HLE_get_NV2A_vertex_attribute_value_pointer(unsigned slot)
|
||||
{
|
||||
NV2AState* dev = g_NV2A->GetDeviceState();
|
||||
PGRAPHState *pg = &(dev->pgraph);
|
||||
|
||||
// See CASE_16(NV097_SET_VERTEX_DATA4UB, 4) in LLE pgraph_handle_method()
|
||||
VertexAttribute *vertex_attribute = &pg->vertex_attributes[slot];
|
||||
// Inverse of D3DDevice_SetVertexDataColor
|
||||
uint8_t a = uint8_t(vertex_attribute->inline_value[0] * 255.0f);
|
||||
uint8_t b = uint8_t(vertex_attribute->inline_value[1] * 255.0f);
|
||||
uint8_t c = uint8_t(vertex_attribute->inline_value[2] * 255.0f);
|
||||
uint8_t d = uint8_t(vertex_attribute->inline_value[3] * 255.0f);
|
||||
uint32_t value = a + (b << 8) + (c << 16) + (d << 24);
|
||||
return vertex_attribute->inline_value;
|
||||
}
|
||||
|
||||
uint32_t HLE_read_NV2A_vertex_program_slot(unsigned program_load, unsigned slot)
|
||||
{
|
||||
NV2AState* dev = g_NV2A->GetDeviceState();
|
||||
PGRAPHState* pg = &(dev->pgraph);
|
||||
|
||||
// See CASE_32(NV097_SET_TRANSFORM_PROGRAM, 4) in LLE pgraph_handle_method()
|
||||
assert(program_load < NV2A_MAX_TRANSFORM_PROGRAM_LENGTH);
|
||||
uint32_t value = pg->program_data[program_load][slot % 4];
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
float *HLE_get_NV2A_vertex_constant_float4_ptr(unsigned const_index)
|
||||
{
|
||||
NV2AState* dev = g_NV2A->GetDeviceState();
|
||||
PGRAPHState* pg = &(dev->pgraph);
|
||||
|
||||
// See CASE_32(NV097_SET_TRANSFORM_CONSTANT, 4) in LLE pgraph_handle_method()
|
||||
assert(const_index < NV2A_VERTEXSHADER_CONSTANTS);
|
||||
return (float*)&(pg->vsh_constants[const_index][0]);
|
||||
}
|
||||
|
||||
// For now, skip the cache, but handle the pgraph method directly
|
||||
// Note : Here's where the method gets multiplied by four!
|
||||
// Note 2 : d is read from local scope, and ni is unused (same in LLE)
|
||||
|
@ -439,8 +365,6 @@ extern void EmuExecutePushBufferRaw
|
|||
uint32_t uSizeInBytes
|
||||
)
|
||||
{
|
||||
HLE_init_pgraph_plugins(); // TODO : Move to more approriate spot
|
||||
|
||||
// Test-case : Azurik (see https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/issues/360)
|
||||
// Test-case : Crash 'n' Burn [45530014]
|
||||
// Test-case : CrimsonSea [4B4F0002]
|
||||
|
|
|
@ -27,9 +27,6 @@
|
|||
|
||||
#include "core/hle/D3D8/XbVertexBuffer.h" // for CxbxDrawContext
|
||||
|
||||
extern int DxbxFVF_GetNumberOfTextureCoordinates(DWORD dwFVF, int aTextureIndex);
|
||||
extern UINT DxbxFVFToVertexSizeInBytes(DWORD dwFVF, BOOL bIncludeTextures);
|
||||
|
||||
extern void CxbxDrawIndexed(CxbxDrawContext &DrawContext);
|
||||
extern void CxbxDrawPrimitiveUP(CxbxDrawContext &DrawContext);
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#include "core\hle\D3D8\Direct3D9\Direct3D9.h" // For g_pD3DDevice
|
||||
#include "core\hle\D3D8\Direct3D9\WalkIndexBuffer.h" // for WalkIndexBuffer
|
||||
#include "core\hle\D3D8\ResourceTracker.h"
|
||||
#include "core\hle\D3D8\XbPushBuffer.h" // for DxbxFVF_GetNumberOfTextureCoordinates
|
||||
#include "core\hle\D3D8\XbPushBuffer.h" // For CxbxDrawPrimitiveUP
|
||||
#include "core\hle\D3D8\XbVertexBuffer.h"
|
||||
#include "core\hle\D3D8\XbConvert.h"
|
||||
|
||||
|
@ -45,16 +45,15 @@
|
|||
#define MAX_STREAM_NOT_USED_TIME (2 * CLOCKS_PER_SEC) // TODO: Trim the not used time
|
||||
|
||||
// Inline vertex buffer emulation
|
||||
extern xbox::X_D3DPRIMITIVETYPE g_InlineVertexBuffer_PrimitiveType = xbox::X_D3DPT_INVALID;
|
||||
extern DWORD g_InlineVertexBuffer_FVF = 0;
|
||||
std::vector<_D3DIVB> g_InlineVertexBuffer_Table;
|
||||
extern UINT g_InlineVertexBuffer_TableLength = 0;
|
||||
extern UINT g_InlineVertexBuffer_TableOffset = 0;
|
||||
|
||||
FLOAT *g_InlineVertexBuffer_pData = nullptr;
|
||||
UINT g_InlineVertexBuffer_DataSize = 0;
|
||||
|
||||
extern DWORD g_dwPrimPerFrame = 0;
|
||||
xbox::X_D3DPRIMITIVETYPE g_InlineVertexBuffer_PrimitiveType = xbox::X_D3DPT_INVALID;
|
||||
uint32_t g_InlineVertexBuffer_WrittenRegisters = 0; // A bitmask, indicating which registers have been set in g_InlineVertexBuffer_Table
|
||||
xbox::X_VERTEXATTRIBUTEFORMAT g_InlineVertexBuffer_AttributeFormat = {};
|
||||
bool g_InlineVertexBuffer_DeclarationOverride = false;
|
||||
std::vector<D3DIVB> g_InlineVertexBuffer_Table;
|
||||
UINT g_InlineVertexBuffer_TableLength = 0;
|
||||
UINT g_InlineVertexBuffer_TableOffset = 0;
|
||||
FLOAT *g_InlineVertexBuffer_pData = nullptr;
|
||||
UINT g_InlineVertexBuffer_DataSize = 0;
|
||||
|
||||
// Copy of active Xbox D3D Vertex Streams (and strides), set by [D3DDevice|CxbxImpl]_SetStreamSource*
|
||||
xbox::X_STREAMINPUT g_Xbox_SetStreamSource[X_VSH_MAX_STREAMS] = { 0 }; // Note : .Offset member is never set (so always 0)
|
||||
|
@ -63,29 +62,12 @@ extern xbox::X_D3DSurface* g_pXbox_RenderTarget;
|
|||
extern xbox::X_D3DSurface* g_pXbox_BackBufferSurface;
|
||||
extern xbox::X_D3DMULTISAMPLE_TYPE g_Xbox_MultiSampleType;
|
||||
|
||||
extern float *HLE_get_NV2A_vertex_attribute_value_pointer(unsigned VertexSlot); // Declared in PushBuffer.cpp
|
||||
|
||||
void *GetDataFromXboxResource(xbox::X_D3DResource *pXboxResource);
|
||||
bool GetHostRenderTargetDimensions(DWORD* pHostWidth, DWORD* pHostHeight, IDirect3DSurface* pHostRenderTarget = nullptr);
|
||||
uint32_t GetPixelContainerWidth(xbox::X_D3DPixelContainer* pPixelContainer);
|
||||
uint32_t GetPixelContainerHeight(xbox::X_D3DPixelContainer* pPixelContainer);
|
||||
void ApplyXboxMultiSampleOffsetAndScale(float& x, float& y);
|
||||
|
||||
_D3DIVB::_D3DIVB()
|
||||
{
|
||||
Position.x = 0.0f;
|
||||
Position.y = 0.0f;
|
||||
Position.z = 0.0f;
|
||||
Rhw = 0.0f;
|
||||
std::fill(std::begin(Blend), std::end(Blend), 0.0f);
|
||||
Normal.x = 0.0f;
|
||||
Normal.y = 0.0f;
|
||||
Normal.z = 0.0f;
|
||||
Diffuse = 0u;
|
||||
Specular = 0u;
|
||||
Fog = 0.0f;
|
||||
BackDiffuse = 0u;
|
||||
BackSpecular = 0u;
|
||||
std::fill(std::begin(TexCoord), std::end(TexCoord), D3DXVECTOR4{ 0.0f , 0.0f, 0.0f, 0.0f });
|
||||
}
|
||||
|
||||
struct _D3DIVB &_D3DIVB::operator=(const struct _D3DIVB &Val)
|
||||
{
|
||||
|
@ -100,14 +82,16 @@ struct _D3DIVB &_D3DIVB::operator=(const struct _D3DIVB &Val)
|
|||
Diffuse = Val.Diffuse;
|
||||
Specular = Val.Specular;
|
||||
Fog = Val.Fog;
|
||||
PointSize = Val.PointSize;
|
||||
BackDiffuse = Val.BackDiffuse;
|
||||
BackSpecular = Val.BackSpecular;
|
||||
std::copy(std::begin(Val.TexCoord), std::end(Val.TexCoord), std::begin(TexCoord));
|
||||
std::copy(std::begin(Val.Reg13Up), std::end(Val.Reg13Up), std::begin(Reg13Up));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void CxbxPatchedStream::Activate(CxbxDrawContext *pDrawContext, UINT uiStream) const
|
||||
void CxbxPatchedStream::Activate(CxbxDrawContext *pDrawContext, UINT HostStreamNumber) const
|
||||
{
|
||||
//LOG_INIT // Allows use of DEBUG_D3DRESULT
|
||||
|
||||
|
@ -119,7 +103,7 @@ void CxbxPatchedStream::Activate(CxbxDrawContext *pDrawContext, UINT uiStream) c
|
|||
}
|
||||
else {
|
||||
HRESULT hRet = g_pD3DDevice->SetStreamSource(
|
||||
uiStream,
|
||||
HostStreamNumber,
|
||||
pCachedHostVertexBuffer,
|
||||
0, // OffsetInBytes
|
||||
uiCachedHostVertexStride);
|
||||
|
@ -136,7 +120,7 @@ CxbxPatchedStream::CxbxPatchedStream()
|
|||
isValid = false;
|
||||
}
|
||||
|
||||
CxbxPatchedStream::~CxbxPatchedStream()
|
||||
void CxbxPatchedStream::Clear()
|
||||
{
|
||||
if (bCachedHostVertexStreamZeroDataIsAllocated) {
|
||||
free(pCachedHostVertexStreamZeroData);
|
||||
|
@ -151,26 +135,30 @@ CxbxPatchedStream::~CxbxPatchedStream()
|
|||
}
|
||||
}
|
||||
|
||||
CxbxPatchedStream::~CxbxPatchedStream()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
CxbxVertexBufferConverter::CxbxVertexBufferConverter()
|
||||
{
|
||||
m_uiNbrStreams = 0;
|
||||
m_pCxbxVertexDeclaration = nullptr;
|
||||
}
|
||||
|
||||
// TODO: CountActiveD3DStreams must be removed once we can rely on CxbxGetVertexDeclaration always being set
|
||||
int CountActiveD3DStreams()
|
||||
{
|
||||
int lastStreamIndex = 0;
|
||||
for (int i = 0; i < X_VSH_MAX_STREAMS; i++) {
|
||||
if (g_Xbox_SetStreamSource[i].VertexBuffer != xbox::zeroptr) {
|
||||
lastStreamIndex = i + 1;
|
||||
int StreamCount = 0;
|
||||
for (int XboxStreamNumber = 0; XboxStreamNumber < X_VSH_MAX_STREAMS; XboxStreamNumber++) {
|
||||
if (GetXboxVertexStreamInput(XboxStreamNumber).VertexBuffer != xbox::zeroptr) {
|
||||
StreamCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return lastStreamIndex;
|
||||
return StreamCount;
|
||||
}
|
||||
|
||||
CxbxVertexDeclaration *GetCxbxVertexDeclaration(DWORD XboxVertexShaderHandle); // forward
|
||||
|
||||
UINT CxbxVertexBufferConverter::GetNbrStreams(CxbxDrawContext *pDrawContext)
|
||||
{
|
||||
// Draw..Up always have one stream
|
||||
|
@ -178,20 +166,12 @@ UINT CxbxVertexBufferConverter::GetNbrStreams(CxbxDrawContext *pDrawContext)
|
|||
return 1;
|
||||
}
|
||||
|
||||
if(VshHandleIsVertexShader(g_Xbox_VertexShader_Handle)) {
|
||||
CxbxVertexDeclaration *pDecl = GetCxbxVertexDeclaration(g_Xbox_VertexShader_Handle);
|
||||
if (pDecl) {
|
||||
if (pDecl->NumberOfVertexStreams <= X_VSH_MAX_STREAMS) {
|
||||
return pDecl->NumberOfVertexStreams;
|
||||
}
|
||||
|
||||
// If we reached here, pDecl was set,but with invalid data
|
||||
LOG_TEST_CASE("NumberOfVertexStreams > 16");
|
||||
}
|
||||
|
||||
return CountActiveD3DStreams();
|
||||
CxbxVertexDeclaration *pDecl = CxbxGetVertexDeclaration();
|
||||
if (pDecl) {
|
||||
return pDecl->NumberOfVertexStreams;
|
||||
}
|
||||
|
||||
// TODO: This code and CountActiveD3DStreams must be removed once we can rely on CxbxGetVertexDeclaration always being set
|
||||
if (g_Xbox_VertexShader_Handle) {
|
||||
return CountActiveD3DStreams();
|
||||
}
|
||||
|
@ -261,60 +241,24 @@ void CxbxVertexBufferConverter::ConvertStream
|
|||
)
|
||||
{
|
||||
extern D3DCAPS g_D3DCaps;
|
||||
|
||||
bool bVshHandleIsFVF = VshHandleIsFVF(g_Xbox_VertexShader_Handle);
|
||||
DWORD XboxFVF = bVshHandleIsFVF ? g_Xbox_VertexShader_Handle : 0;
|
||||
// Texture normalization can only be set for FVF shaders
|
||||
bool bNeedTextureNormalization = false;
|
||||
struct { int NrTexCoords; bool bTexIsLinear; int Width; int Height; int Depth; } pActivePixelContainer[xbox::X_D3DTS_STAGECOUNT] = { 0 };
|
||||
|
||||
if (bVshHandleIsFVF) {
|
||||
DWORD dwTexN = (XboxFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
|
||||
if (dwTexN > xbox::X_D3DTS_STAGECOUNT) {
|
||||
LOG_TEST_CASE("FVF,dwTexN > X_D3DTS_STAGECOUNT");
|
||||
}
|
||||
|
||||
// Check for active linear textures.
|
||||
//X_D3DBaseTexture *pLinearBaseTexture[xbox::X_D3DTS_STAGECOUNT];
|
||||
for (unsigned int i = 0; i < xbox::X_D3DTS_STAGECOUNT; i++) {
|
||||
// Only normalize coordinates used by the FVF shader :
|
||||
if (i + 1 <= dwTexN) {
|
||||
pActivePixelContainer[i].NrTexCoords = DxbxFVF_GetNumberOfTextureCoordinates(XboxFVF, i);
|
||||
// TODO : Use GetXboxBaseTexture()
|
||||
xbox::X_D3DBaseTexture *pXboxBaseTexture = g_pXbox_SetTexture[i];
|
||||
if (pXboxBaseTexture != xbox::zeroptr) {
|
||||
extern xbox::X_D3DFORMAT GetXboxPixelContainerFormat(const xbox::X_D3DPixelContainer *pXboxPixelContainer); // TODO : Move to XTL-independent header file
|
||||
|
||||
xbox::X_D3DFORMAT XboxFormat = GetXboxPixelContainerFormat(pXboxBaseTexture);
|
||||
if (EmuXBFormatIsLinear(XboxFormat)) {
|
||||
// This is often hit by the help screen in XDK samples.
|
||||
bNeedTextureNormalization = true;
|
||||
// Remember linearity, width and height :
|
||||
pActivePixelContainer[i].bTexIsLinear = true;
|
||||
// TODO : Use DecodeD3DSize or GetPixelContainerWidth + GetPixelContainerHeight
|
||||
pActivePixelContainer[i].Width = (pXboxBaseTexture->Size & X_D3DSIZE_WIDTH_MASK) + 1;
|
||||
pActivePixelContainer[i].Height = ((pXboxBaseTexture->Size & X_D3DSIZE_HEIGHT_MASK) >> X_D3DSIZE_HEIGHT_SHIFT) + 1;
|
||||
// TODO : Support 3D textures
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CxbxVertexShaderStreamInfo *pVertexShaderStreamInfo = nullptr;
|
||||
UINT XboxStreamNumber = uiStream;
|
||||
if (m_pCxbxVertexDeclaration != nullptr) {
|
||||
if (uiStream > m_pCxbxVertexDeclaration->NumberOfVertexStreams + 1) {
|
||||
if (uiStream > m_pCxbxVertexDeclaration->NumberOfVertexStreams) {
|
||||
LOG_TEST_CASE("uiStream > NumberOfVertexStreams");
|
||||
return;
|
||||
}
|
||||
|
||||
pVertexShaderStreamInfo = &(m_pCxbxVertexDeclaration->VertexStreams[uiStream]);
|
||||
XboxStreamNumber = pVertexShaderStreamInfo->XboxStreamIndex;
|
||||
}
|
||||
|
||||
bool bNeedVertexPatching = (pVertexShaderStreamInfo != nullptr && pVertexShaderStreamInfo->NeedPatch);
|
||||
bool bNeedRHWReset = bVshHandleIsFVF && ((XboxFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW);
|
||||
bool bNeedStreamCopy = bNeedTextureNormalization || bNeedVertexPatching || bNeedRHWReset;
|
||||
bool bNeedStreamCopy = bNeedVertexPatching;
|
||||
|
||||
UINT HostStreamNumber = XboxStreamNumber; // Use Xbox stream index on host
|
||||
uint8_t *pXboxVertexData = xbox::zeroptr;
|
||||
UINT uiXboxVertexStride = 0;
|
||||
UINT uiVertexCount = 0;
|
||||
|
@ -325,7 +269,7 @@ void CxbxVertexBufferConverter::ConvertStream
|
|||
|
||||
if (pDrawContext->pXboxVertexStreamZeroData != xbox::zeroptr) {
|
||||
// There should only be one stream (stream zero) in this case
|
||||
if (uiStream != 0) {
|
||||
if (XboxStreamNumber != 0) {
|
||||
CxbxKrnlCleanup("Trying to patch a Draw..UP with more than stream zero!");
|
||||
}
|
||||
|
||||
|
@ -335,23 +279,24 @@ void CxbxVertexBufferConverter::ConvertStream
|
|||
uiHostVertexStride = (bNeedVertexPatching) ? pVertexShaderStreamInfo->HostVertexStride : uiXboxVertexStride;
|
||||
dwHostVertexDataSize = uiVertexCount * uiHostVertexStride;
|
||||
} else {
|
||||
xbox::X_D3DVertexBuffer *pXboxVertexBuffer = g_Xbox_SetStreamSource[uiStream].VertexBuffer;
|
||||
xbox::X_STREAMINPUT& XboxStreamInput = GetXboxVertexStreamInput(XboxStreamNumber);
|
||||
xbox::X_D3DVertexBuffer *pXboxVertexBuffer = XboxStreamInput.VertexBuffer;
|
||||
pXboxVertexData = (uint8_t*)GetDataFromXboxResource(pXboxVertexBuffer);
|
||||
if (pXboxVertexData == xbox::zeroptr) {
|
||||
HRESULT hRet = g_pD3DDevice->SetStreamSource(
|
||||
uiStream,
|
||||
HostStreamNumber,
|
||||
nullptr,
|
||||
0, // OffsetInBytes
|
||||
0);
|
||||
// DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetStreamSource");
|
||||
if (FAILED(hRet)) {
|
||||
EmuLog(LOG_LEVEL::WARNING, "g_pD3DDevice->SetStreamSource(uiStream, nullptr, 0)");
|
||||
EmuLog(LOG_LEVEL::WARNING, "g_pD3DDevice->SetStreamSource(HostStreamNumber, nullptr, 0)");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uiXboxVertexStride = g_Xbox_SetStreamSource[uiStream].Stride;
|
||||
uiXboxVertexStride = XboxStreamInput.Stride;
|
||||
// Set a new (exact) vertex count
|
||||
uiVertexCount = pDrawContext->VerticesInBuffer;
|
||||
// Dxbx note : Don't overwrite pDrawContext.dwVertexCount with uiVertexCount, because an indexed draw
|
||||
|
@ -376,7 +321,7 @@ void CxbxVertexBufferConverter::ConvertStream
|
|||
stream.uiCachedHostVertexStride = uiHostVertexStride;
|
||||
stream.bCacheIsStreamZeroDrawUP = true;
|
||||
stream.pCachedHostVertexStreamZeroData = pHostVertexData;
|
||||
stream.Activate(pDrawContext, uiStream);
|
||||
stream.Activate(pDrawContext, HostStreamNumber);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -400,26 +345,17 @@ void CxbxVertexBufferConverter::ConvertStream
|
|||
patchedStream.uiCachedXboxVertexStride == uiXboxVertexStride && // Make sure the Xbox Stride didn't change
|
||||
patchedStream.uiCachedXboxVertexDataSize == xboxVertexDataSize ) { // Make sure the Xbox Data Size also didn't change
|
||||
m_TotalCacheHits++;
|
||||
patchedStream.Activate(pDrawContext, uiStream);
|
||||
patchedStream.Activate(pDrawContext, HostStreamNumber);
|
||||
return;
|
||||
}
|
||||
|
||||
m_TotalCacheMisses++;
|
||||
|
||||
// If execution reaches here, the cached vertex buffer was not valid and we must reconvert the data
|
||||
if (patchedStream.isValid) {
|
||||
pHostVertexData = (uint8_t*)patchedStream.pCachedHostVertexStreamZeroData;
|
||||
pNewHostVertexBuffer = patchedStream.pCachedHostVertexBuffer;
|
||||
|
||||
// Free the existing buffers
|
||||
if (pHostVertexData != nullptr) {
|
||||
free(pHostVertexData);
|
||||
pHostVertexData = nullptr;
|
||||
} else if (pNewHostVertexBuffer != nullptr) {
|
||||
pNewHostVertexBuffer->Release();
|
||||
pNewHostVertexBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
// Free the existing buffers
|
||||
patchedStream.Clear();
|
||||
assert(pHostVertexData == nullptr);
|
||||
assert(pNewHostVertexBuffer == nullptr);
|
||||
|
||||
// If dwHostVertexDataSize is zero, the allocation/creation will fail
|
||||
// This can be caused by a stride of 0, and 'other' invalid configurations
|
||||
|
@ -478,9 +414,7 @@ void CxbxVertexBufferConverter::ConvertStream
|
|||
// Make it SHORT2N
|
||||
pHostVertexAsShort[0] = pXboxVertexAsShort[0];
|
||||
pHostVertexAsShort[1] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Make it FLOAT1
|
||||
pHostVertexAsFloat[0] = NormShortToFloat(pXboxVertexAsShort[0]);
|
||||
//pHostVertexAsFloat[1] = 0.0f; // Would be needed for FLOAT2
|
||||
|
@ -496,9 +430,7 @@ void CxbxVertexBufferConverter::ConvertStream
|
|||
// Make it SHORT2N
|
||||
pHostVertexAsShort[0] = pXboxVertexAsShort[0];
|
||||
pHostVertexAsShort[1] = pXboxVertexAsShort[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Make it FLOAT2
|
||||
pHostVertexAsFloat[0] = NormShortToFloat(pXboxVertexAsShort[0]);
|
||||
pHostVertexAsFloat[1] = NormShortToFloat(pXboxVertexAsShort[1]);
|
||||
|
@ -513,9 +445,7 @@ void CxbxVertexBufferConverter::ConvertStream
|
|||
pHostVertexAsShort[1] = pXboxVertexAsShort[1];
|
||||
pHostVertexAsShort[2] = pXboxVertexAsShort[2];
|
||||
pHostVertexAsShort[3] = 32767; // TODO : verify
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Make it FLOAT3
|
||||
pHostVertexAsFloat[0] = NormShortToFloat(pXboxVertexAsShort[0]);
|
||||
pHostVertexAsFloat[1] = NormShortToFloat(pXboxVertexAsShort[1]);
|
||||
|
@ -534,9 +464,7 @@ void CxbxVertexBufferConverter::ConvertStream
|
|||
pHostVertexAsShort[1] = pXboxVertexAsShort[1];
|
||||
pHostVertexAsShort[2] = pXboxVertexAsShort[2];
|
||||
pHostVertexAsShort[3] = pXboxVertexAsShort[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Make it FLOAT4
|
||||
pHostVertexAsFloat[0] = NormShortToFloat(pXboxVertexAsShort[0]);
|
||||
pHostVertexAsFloat[1] = NormShortToFloat(pXboxVertexAsShort[1]);
|
||||
|
@ -586,9 +514,7 @@ void CxbxVertexBufferConverter::ConvertStream
|
|||
pHostVertexAsByte[1] = 0;
|
||||
pHostVertexAsByte[2] = 0;
|
||||
pHostVertexAsByte[3] = 255; // TODO : Verify
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Make it FLOAT1
|
||||
pHostVertexAsFloat[0] = ByteToFloat(pXboxVertexAsByte[0]);
|
||||
}
|
||||
|
@ -601,9 +527,7 @@ void CxbxVertexBufferConverter::ConvertStream
|
|||
pHostVertexAsByte[1] = pXboxVertexAsByte[1];
|
||||
pHostVertexAsByte[2] = 0;
|
||||
pHostVertexAsByte[3] = 255; // TODO : Verify
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Make it FLOAT2
|
||||
pHostVertexAsFloat[0] = ByteToFloat(pXboxVertexAsByte[0]);
|
||||
pHostVertexAsFloat[1] = ByteToFloat(pXboxVertexAsByte[1]);
|
||||
|
@ -618,9 +542,7 @@ void CxbxVertexBufferConverter::ConvertStream
|
|||
pHostVertexAsByte[1] = pXboxVertexAsByte[1];
|
||||
pHostVertexAsByte[2] = pXboxVertexAsByte[2];
|
||||
pHostVertexAsByte[3] = 255; // TODO : Verify
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Make it FLOAT3
|
||||
pHostVertexAsFloat[0] = ByteToFloat(pXboxVertexAsByte[0]);
|
||||
pHostVertexAsFloat[1] = ByteToFloat(pXboxVertexAsByte[1]);
|
||||
|
@ -639,9 +561,7 @@ void CxbxVertexBufferConverter::ConvertStream
|
|||
pHostVertexAsByte[1] = pXboxVertexAsByte[1];
|
||||
pHostVertexAsByte[2] = pXboxVertexAsByte[2];
|
||||
pHostVertexAsByte[3] = pXboxVertexAsByte[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Make it FLOAT4
|
||||
pHostVertexAsFloat[0] = ByteToFloat(pXboxVertexAsByte[0]);
|
||||
pHostVertexAsFloat[1] = ByteToFloat(pXboxVertexAsByte[1]);
|
||||
|
@ -685,105 +605,6 @@ void CxbxVertexBufferConverter::ConvertStream
|
|||
}
|
||||
}
|
||||
|
||||
// Xbox FVF shaders are identical to host Direct3D 8.1, however
|
||||
// texture coordinates may need normalization if used with linear textures.
|
||||
if (bNeedTextureNormalization || bNeedRHWReset) {
|
||||
// assert(bVshHandleIsFVF);
|
||||
|
||||
UINT uiTextureCoordinatesByteOffsetInVertex = 0;
|
||||
|
||||
// Locate texture coordinate offset in vertex structure.
|
||||
if (bNeedTextureNormalization) {
|
||||
uiTextureCoordinatesByteOffsetInVertex = DxbxFVFToVertexSizeInBytes(XboxFVF, /*bIncludeTextures=*/false);
|
||||
if (bNeedVertexPatching) {
|
||||
LOG_TEST_CASE("Potential xbox vs host texture-offset difference! (bNeedVertexPatching within bNeedTextureNormalization)");
|
||||
}
|
||||
// As long as vertices aren't resized / patched up until the texture coordinates,
|
||||
// the uiTextureCoordinatesByteOffsetInVertex on host will match Xbox
|
||||
}
|
||||
|
||||
// If for some reason the Xbox Render Target is not set, fallback to the backbuffer
|
||||
if (g_pXbox_RenderTarget == xbox::zeroptr) {
|
||||
LOG_TEST_CASE("SetRenderTarget fallback to backbuffer");
|
||||
g_pXbox_RenderTarget = g_pXbox_BackBufferSurface;
|
||||
}
|
||||
|
||||
DWORD HostRenderTarget_Width, HostRenderTarget_Height;
|
||||
DWORD XboxRenderTarget_Width = GetPixelContainerWidth(g_pXbox_RenderTarget);
|
||||
DWORD XboxRenderTarget_Height = GetPixelContainerHeight(g_pXbox_RenderTarget);
|
||||
if (!GetHostRenderTargetDimensions(&HostRenderTarget_Width, &HostRenderTarget_Height)) {
|
||||
HostRenderTarget_Width = XboxRenderTarget_Width;
|
||||
HostRenderTarget_Height = XboxRenderTarget_Height;
|
||||
}
|
||||
|
||||
bool bNeedRHWTransform = (g_Xbox_MultiSampleType > xbox::X_D3DMULTISAMPLE_NONE) || (XboxRenderTarget_Width < HostRenderTarget_Width && XboxRenderTarget_Height < HostRenderTarget_Height);
|
||||
|
||||
for (uint32_t uiVertex = 0; uiVertex < uiVertexCount; uiVertex++) {
|
||||
FLOAT *pVertexDataAsFloat = (FLOAT*)(&pHostVertexData[uiVertex * uiHostVertexStride]);
|
||||
|
||||
// Handle pre-transformed vertices (which bypass the vertex shader pipeline)
|
||||
if (bNeedRHWReset) {
|
||||
// We need to transform these vertices only if the host render target was upscaled from the Xbox render target
|
||||
// Transforming always breaks render to non-upscaled textures: Only surfaces are upscaled, intentionally so
|
||||
if (bNeedRHWTransform) {
|
||||
pVertexDataAsFloat[0] *= g_RenderScaleFactor;
|
||||
pVertexDataAsFloat[1] *= g_RenderScaleFactor;
|
||||
|
||||
ApplyXboxMultiSampleOffsetAndScale(pVertexDataAsFloat[0], pVertexDataAsFloat[1]);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Check Z. TODO : Why reset Z from 0.0 to 1.0 ? (Maybe fog-related?)
|
||||
if (pVertexDataAsFloat[2] == 0.0f) {
|
||||
// LOG_TEST_CASE("D3DFVF_XYZRHW (Z)"); // Test-case : Many XDK Samples (AlphaFog, PointSprites)
|
||||
pVertexDataAsFloat[2] = 1.0f;
|
||||
}
|
||||
#endif
|
||||
#if 1
|
||||
// Check RHW. TODO : Why reset from 0.0 to 1.0 ? (Maybe 1.0 indicates that the vertices are not to be transformed)
|
||||
if (pVertexDataAsFloat[3] == 0.0f) {
|
||||
// LOG_TEST_CASE("D3DFVF_XYZRHW (RHW)"); // Test-case : Many XDK Samples (AlphaFog, PointSprites)
|
||||
pVertexDataAsFloat[3] = 1.0f;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Normalize texture coordinates in FVF stream if needed
|
||||
if (uiTextureCoordinatesByteOffsetInVertex > 0) { // implies bNeedTextureNormalization (using one is more efficient than both)
|
||||
FLOAT *pVertexUVData = (FLOAT*)((uintptr_t)pVertexDataAsFloat + uiTextureCoordinatesByteOffsetInVertex);
|
||||
for (unsigned int i = 0; i < xbox::X_D3DTS_STAGECOUNT; i++) {
|
||||
if (pActivePixelContainer[i].bTexIsLinear) {
|
||||
switch (pActivePixelContainer[i].NrTexCoords) {
|
||||
case 0:
|
||||
LOG_TEST_CASE("Normalize 0D?");
|
||||
break;
|
||||
case 1:
|
||||
LOG_TEST_CASE("Normalize 1D");
|
||||
pVertexUVData[0] /= pActivePixelContainer[i].Width;
|
||||
break;
|
||||
case 2:
|
||||
pVertexUVData[0] /= pActivePixelContainer[i].Width;
|
||||
pVertexUVData[1] /= pActivePixelContainer[i].Height;
|
||||
break;
|
||||
case 3:
|
||||
LOG_TEST_CASE("Normalize 3D");
|
||||
// Test case : HeatShimmer
|
||||
pVertexUVData[0] /= pActivePixelContainer[i].Width;
|
||||
pVertexUVData[1] /= pActivePixelContainer[i].Height;
|
||||
pVertexUVData[2] /= pActivePixelContainer[i].Depth;
|
||||
break;
|
||||
default:
|
||||
LOG_TEST_CASE("Normalize ?D");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pVertexUVData += pActivePixelContainer[i].NrTexCoords;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
patchedStream.isValid = true;
|
||||
patchedStream.XboxPrimitiveType = pDrawContext->XboxPrimitiveType;
|
||||
patchedStream.pCachedXboxVertexData = pXboxVertexData;
|
||||
|
@ -802,7 +623,7 @@ void CxbxVertexBufferConverter::ConvertStream
|
|||
patchedStream.pCachedHostVertexBuffer = pNewHostVertexBuffer;
|
||||
}
|
||||
|
||||
patchedStream.Activate(pDrawContext, uiStream);
|
||||
patchedStream.Activate(pDrawContext, HostStreamNumber);
|
||||
}
|
||||
|
||||
void CxbxVertexBufferConverter::Apply(CxbxDrawContext *pDrawContext)
|
||||
|
@ -810,10 +631,7 @@ void CxbxVertexBufferConverter::Apply(CxbxDrawContext *pDrawContext)
|
|||
if ((pDrawContext->XboxPrimitiveType < xbox::X_D3DPT_POINTLIST) || (pDrawContext->XboxPrimitiveType > xbox::X_D3DPT_POLYGON))
|
||||
CxbxKrnlCleanup("Unknown primitive type: 0x%.02X\n", pDrawContext->XboxPrimitiveType);
|
||||
|
||||
m_pCxbxVertexDeclaration = nullptr;
|
||||
if (VshHandleIsVertexShader(g_Xbox_VertexShader_Handle)) {
|
||||
m_pCxbxVertexDeclaration = &(GetCxbxVertexShader(g_Xbox_VertexShader_Handle)->Declaration);
|
||||
}
|
||||
m_pCxbxVertexDeclaration = CxbxGetVertexDeclaration();
|
||||
|
||||
// If we are drawing from an offset, we know that the vertex count must have
|
||||
// 'offset' vertices before the first drawn vertices
|
||||
|
@ -841,8 +659,8 @@ void CxbxVertexBufferConverter::Apply(CxbxDrawContext *pDrawContext)
|
|||
m_uiNbrStreams = X_VSH_MAX_STREAMS;
|
||||
}
|
||||
|
||||
for(UINT uiStream = 0; uiStream < m_uiNbrStreams; uiStream++) {
|
||||
ConvertStream(pDrawContext, uiStream);
|
||||
for(UINT i = 0; i < m_uiNbrStreams; i++) {
|
||||
ConvertStream(pDrawContext, i);
|
||||
}
|
||||
|
||||
if (pDrawContext->XboxPrimitiveType == xbox::X_D3DPT_QUADSTRIP) {
|
||||
|
@ -869,48 +687,128 @@ void CxbxVertexBufferConverter::Apply(CxbxDrawContext *pDrawContext)
|
|||
}
|
||||
}
|
||||
|
||||
void EmuFlushIVB()
|
||||
void CxbxSetVertexAttribute(int Register, FLOAT a, FLOAT b, FLOAT c, FLOAT d)
|
||||
{
|
||||
CxbxUpdateNativeD3DResources();
|
||||
|
||||
// Parse IVB table with current FVF shader if possible.
|
||||
bool bFVF = VshHandleIsFVF(g_Xbox_VertexShader_Handle);
|
||||
DWORD dwCurFVF = (bFVF) ? g_Xbox_VertexShader_Handle : g_InlineVertexBuffer_FVF;
|
||||
|
||||
EmuLog(LOG_LEVEL::DEBUG, "g_InlineVertexBuffer_TableOffset := %d", g_InlineVertexBuffer_TableOffset);
|
||||
|
||||
// Check the given FVF
|
||||
switch (dwCurFVF & D3DFVF_POSITION_MASK) {
|
||||
case 0: // No position ?
|
||||
if (bFVF) {
|
||||
EmuLog(LOG_LEVEL::WARNING, "EmuFlushIVB(): g_Xbox_VertexShader_Handle isn't a valid FVF - using D3DFVF_XYZRHW instead!");
|
||||
dwCurFVF |= D3DFVF_XYZRHW;
|
||||
}
|
||||
else {
|
||||
EmuLog(LOG_LEVEL::WARNING, "EmuFlushIVB(): using g_InlineVertexBuffer_FVF instead of current FVF!");
|
||||
dwCurFVF = g_InlineVertexBuffer_FVF;
|
||||
}
|
||||
break;
|
||||
case D3DFVF_XYZRHW:
|
||||
// D3DFVF_NORMAL isn't allowed in combination with D3DFVF_XYZRHW
|
||||
if (dwCurFVF & D3DFVF_NORMAL) {
|
||||
EmuLog(LOG_LEVEL::WARNING, "EmuFlushIVB(): Normal encountered while D3DFVF_XYZRHW is given - switching back to D3DFVF_XYZ!");
|
||||
dwCurFVF &= ~D3DFVF_POSITION_MASK;
|
||||
dwCurFVF |= D3DFVF_XYZ;
|
||||
}
|
||||
break;
|
||||
if (Register < 0) {
|
||||
LOG_TEST_CASE("Register < 0");
|
||||
return;
|
||||
}
|
||||
if (Register >= 16) {
|
||||
LOG_TEST_CASE("Register >= 16");
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD dwPos = dwCurFVF & D3DFVF_POSITION_MASK;
|
||||
DWORD dwTexN = (dwCurFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
|
||||
size_t TexSize[xbox::X_D3DTS_STAGECOUNT]; // Xbox supports up to 4 textures
|
||||
// Write these values to the NV2A registers, so that we read them back when needed
|
||||
float* attribute_floats = HLE_get_NV2A_vertex_attribute_value_pointer(Register);
|
||||
attribute_floats[0] = a;
|
||||
attribute_floats[1] = b;
|
||||
attribute_floats[2] = c;
|
||||
attribute_floats[3] = d;
|
||||
|
||||
for (unsigned int i = 0; i < dwTexN; i++) {
|
||||
TexSize[i] = DxbxFVF_GetNumberOfTextureCoordinates(dwCurFVF, i);
|
||||
// Also, write the given register value to a matching host vertex shader constant
|
||||
// This allows us to implement Xbox functionality where SetVertexData4f can be used to specify attributes
|
||||
// not present in the vertex declaration.
|
||||
// We use range 193 and up to store these values, as Xbox shaders stop at c192!
|
||||
g_pD3DDevice->SetVertexShaderConstantF(CXBX_D3DVS_CONSTREG_VREGDEFAULTS_BASE + Register, attribute_floats, 1);
|
||||
}
|
||||
|
||||
DWORD Float4ToDWORD(float* floats)
|
||||
{
|
||||
// Inverse of D3DDevice_SetVertexDataColor
|
||||
uint8_t a = uint8_t(floats[0] * 255.0f);
|
||||
uint8_t b = uint8_t(floats[1] * 255.0f);
|
||||
uint8_t c = uint8_t(floats[2] * 255.0f);
|
||||
uint8_t d = uint8_t(floats[3] * 255.0f);
|
||||
uint32_t value = a + (b << 8) + (c << 16) + (d << 24);
|
||||
return value;
|
||||
}
|
||||
|
||||
void CxbxImpl_Begin(xbox::X_D3DPRIMITIVETYPE PrimitiveType)
|
||||
{
|
||||
g_InlineVertexBuffer_PrimitiveType = PrimitiveType;
|
||||
g_InlineVertexBuffer_TableOffset = 0;
|
||||
g_InlineVertexBuffer_WrittenRegisters = 0;
|
||||
}
|
||||
|
||||
void CxbxImpl_End()
|
||||
{
|
||||
using namespace xbox;
|
||||
|
||||
#ifndef FIELD_OFFSET
|
||||
#define FIELD_OFFSET(type, field) ((LONG)(LONG_PTR)&(((type *)0)->field))
|
||||
#endif
|
||||
static const LONG OffsetPerRegister[X_VSH_MAX_ATTRIBUTES] = {
|
||||
/*X_D3DVSDE_POSITION = 0:*/FIELD_OFFSET(D3DIVB, Position),
|
||||
/*X_D3DVSDE_BLENDWEIGHT = 1:*/FIELD_OFFSET(D3DIVB, Blend),
|
||||
/*X_D3DVSDE_NORMAL = 2:*/FIELD_OFFSET(D3DIVB, Normal),
|
||||
/*X_D3DVSDE_DIFFUSE = 3:*/FIELD_OFFSET(D3DIVB, Diffuse),
|
||||
/*X_D3DVSDE_SPECULAR = 4:*/FIELD_OFFSET(D3DIVB, Specular),
|
||||
/*X_D3DVSDE_FOG = 5:*/FIELD_OFFSET(D3DIVB, Fog),
|
||||
/*X_D3DVSDE_POINTSIZE = 6:*/FIELD_OFFSET(D3DIVB, PointSize),
|
||||
/*X_D3DVSDE_BACKDIFFUSE = 7:*/FIELD_OFFSET(D3DIVB, BackDiffuse),
|
||||
/*X_D3DVSDE_BACKSPECULAR = 8:*/FIELD_OFFSET(D3DIVB, BackSpecular),
|
||||
/*X_D3DVSDE_TEXCOORD0 = 9:*/FIELD_OFFSET(D3DIVB, TexCoord[0]),
|
||||
/*X_D3DVSDE_TEXCOORD1 = 10:*/FIELD_OFFSET(D3DIVB, TexCoord[1]),
|
||||
/*X_D3DVSDE_TEXCOORD2 = 11:*/FIELD_OFFSET(D3DIVB, TexCoord[2]),
|
||||
/*X_D3DVSDE_TEXCOORD3 = 12:*/FIELD_OFFSET(D3DIVB, TexCoord[3]),
|
||||
/* 13:*/FIELD_OFFSET(D3DIVB, Reg13Up[0]),
|
||||
/* 14:*/FIELD_OFFSET(D3DIVB, Reg13Up[1]),
|
||||
/* 15:*/FIELD_OFFSET(D3DIVB, Reg13Up[2])
|
||||
};
|
||||
static const LONG FormatPerRegister[X_VSH_MAX_ATTRIBUTES] = {
|
||||
/*X_D3DVSDE_POSITION = 0:*/X_D3DVSDT_FLOAT4,
|
||||
/*X_D3DVSDE_BLENDWEIGHT = 1:*/X_D3DVSDT_FLOAT4,
|
||||
/*X_D3DVSDE_NORMAL = 2:*/X_D3DVSDT_FLOAT3,
|
||||
/*X_D3DVSDE_DIFFUSE = 3:*/X_D3DVSDT_D3DCOLOR,
|
||||
/*X_D3DVSDE_SPECULAR = 4:*/X_D3DVSDT_D3DCOLOR,
|
||||
/*X_D3DVSDE_FOG = 5:*/X_D3DVSDT_FLOAT1,
|
||||
/*X_D3DVSDE_POINTSIZE = 6:*/X_D3DVSDT_FLOAT1,
|
||||
/*X_D3DVSDE_BACKDIFFUSE = 7:*/X_D3DVSDT_D3DCOLOR,
|
||||
/*X_D3DVSDE_BACKSPECULAR = 8:*/X_D3DVSDT_D3DCOLOR,
|
||||
/*X_D3DVSDE_TEXCOORD0 = 9:*/X_D3DVSDT_FLOAT4,
|
||||
/*X_D3DVSDE_TEXCOORD1 = 10:*/X_D3DVSDT_FLOAT4,
|
||||
/*X_D3DVSDE_TEXCOORD2 = 11:*/X_D3DVSDT_FLOAT4,
|
||||
/*X_D3DVSDE_TEXCOORD3 = 12:*/X_D3DVSDT_FLOAT4,
|
||||
/* 13:*/X_D3DVSDT_FLOAT4,
|
||||
/* 14:*/X_D3DVSDT_FLOAT4,
|
||||
/* 15:*/X_D3DVSDT_FLOAT4
|
||||
};
|
||||
static const DWORD SizePerRegister[X_VSH_MAX_ATTRIBUTES] = {
|
||||
/*X_D3DVSDE_POSITION = 0:*/sizeof(float) * 4,
|
||||
/*X_D3DVSDE_BLENDWEIGHT = 1:*/sizeof(float) * 4,
|
||||
/*X_D3DVSDE_NORMAL = 2:*/sizeof(float) * 3,
|
||||
/*X_D3DVSDE_DIFFUSE = 3:*/sizeof(DWORD),
|
||||
/*X_D3DVSDE_SPECULAR = 4:*/sizeof(DWORD),
|
||||
/*X_D3DVSDE_FOG = 5:*/sizeof(float) * 1,
|
||||
/*X_D3DVSDE_POINTSIZE = 6:*/sizeof(float) * 1,
|
||||
/*X_D3DVSDE_BACKDIFFUSE = 7:*/sizeof(DWORD),
|
||||
/*X_D3DVSDE_BACKSPECULAR = 8:*/sizeof(DWORD),
|
||||
/*X_D3DVSDE_TEXCOORD0 = 9:*/sizeof(float) * 4,
|
||||
/*X_D3DVSDE_TEXCOORD1 = 10:*/sizeof(float) * 4,
|
||||
/*X_D3DVSDE_TEXCOORD2 = 11:*/sizeof(float) * 4,
|
||||
/*X_D3DVSDE_TEXCOORD3 = 12:*/sizeof(float) * 4,
|
||||
/* 13:*/sizeof(float) * 4,
|
||||
/* 14:*/sizeof(float) * 4,
|
||||
/* 15:*/sizeof(float) * 4
|
||||
};
|
||||
|
||||
if (g_InlineVertexBuffer_TableOffset <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Compose an Xbox vertex attribute format according to the registers that have been written to :
|
||||
UINT uiStride = 0;
|
||||
g_InlineVertexBuffer_AttributeFormat = {};
|
||||
for (int reg = 0; reg < X_VSH_MAX_ATTRIBUTES; reg++) {
|
||||
if (g_InlineVertexBuffer_WrittenRegisters & (1 << reg)) {
|
||||
g_InlineVertexBuffer_AttributeFormat.Slots[reg].Format = FormatPerRegister[reg];
|
||||
g_InlineVertexBuffer_AttributeFormat.Slots[reg].Offset = uiStride;
|
||||
uiStride += SizePerRegister[reg];
|
||||
} else {
|
||||
g_InlineVertexBuffer_AttributeFormat.Slots[reg].Format = X_D3DVSDT_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// Use a tooling function to determine the vertex stride :
|
||||
UINT uiStride = DxbxFVFToVertexSizeInBytes(dwCurFVF, /*bIncludeTextures=*/true);
|
||||
// Make sure the output buffer is big enough
|
||||
UINT NeededSize = g_InlineVertexBuffer_TableOffset * uiStride;
|
||||
if (g_InlineVertexBuffer_DataSize < NeededSize) {
|
||||
|
@ -922,102 +820,37 @@ void EmuFlushIVB()
|
|||
g_InlineVertexBuffer_pData = (FLOAT*)malloc(g_InlineVertexBuffer_DataSize);
|
||||
}
|
||||
|
||||
FLOAT *pVertexBufferData = g_InlineVertexBuffer_pData;
|
||||
for(unsigned int v=0;v<g_InlineVertexBuffer_TableOffset;v++) {
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Position.x;
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Position.y;
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Position.z;
|
||||
if (dwPos == D3DFVF_XYZRHW) {
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Rhw;
|
||||
EmuLog(LOG_LEVEL::DEBUG, "IVB Position := {%f, %f, %f, %f}", g_InlineVertexBuffer_Table[v].Position.x, g_InlineVertexBuffer_Table[v].Position.y, g_InlineVertexBuffer_Table[v].Position.z, g_InlineVertexBuffer_Table[v].Rhw);
|
||||
}
|
||||
else { // XYZRHW cannot be combined with NORMAL, but the other XYZ formats can :
|
||||
switch (dwPos) {
|
||||
case D3DFVF_XYZ:
|
||||
EmuLog(LOG_LEVEL::DEBUG, "IVB Position := {%f, %f, %f}", g_InlineVertexBuffer_Table[v].Position.x, g_InlineVertexBuffer_Table[v].Position.y, g_InlineVertexBuffer_Table[v].Position.z);
|
||||
break;
|
||||
case D3DFVF_XYZB1:
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Blend[0];
|
||||
EmuLog(LOG_LEVEL::DEBUG, "IVB Position := {%f, %f, %f, %f}", g_InlineVertexBuffer_Table[v].Position.x, g_InlineVertexBuffer_Table[v].Position.y, g_InlineVertexBuffer_Table[v].Position.z, g_InlineVertexBuffer_Table[v].Blend[0]);
|
||||
break;
|
||||
case D3DFVF_XYZB2:
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Blend[0];
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Blend[1];
|
||||
EmuLog(LOG_LEVEL::DEBUG, "IVB Position := {%f, %f, %f, %f, %f}", g_InlineVertexBuffer_Table[v].Position.x, g_InlineVertexBuffer_Table[v].Position.y, g_InlineVertexBuffer_Table[v].Position.z, g_InlineVertexBuffer_Table[v].Blend[0], g_InlineVertexBuffer_Table[v].Blend[1]);
|
||||
break;
|
||||
case D3DFVF_XYZB3:
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Blend[0];
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Blend[1];
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Blend[2];
|
||||
EmuLog(LOG_LEVEL::DEBUG, "IVB Position := {%f, %f, %f, %f, %f, %f}", g_InlineVertexBuffer_Table[v].Position.x, g_InlineVertexBuffer_Table[v].Position.y, g_InlineVertexBuffer_Table[v].Position.z, g_InlineVertexBuffer_Table[v].Blend[0], g_InlineVertexBuffer_Table[v].Blend[1], g_InlineVertexBuffer_Table[v].Blend[2]);
|
||||
break;
|
||||
case D3DFVF_XYZB4:
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Blend[0];
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Blend[1];
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Blend[2];
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Blend[3];
|
||||
EmuLog(LOG_LEVEL::DEBUG, "IVB Position := {%f, %f, %f, %f, %f, %f, %f}", g_InlineVertexBuffer_Table[v].Position.x, g_InlineVertexBuffer_Table[v].Position.y, g_InlineVertexBuffer_Table[v].Position.z, g_InlineVertexBuffer_Table[v].Blend[0], g_InlineVertexBuffer_Table[v].Blend[1], g_InlineVertexBuffer_Table[v].Blend[2], g_InlineVertexBuffer_Table[v].Blend[3]);
|
||||
break;
|
||||
default:
|
||||
CxbxKrnlCleanup("Unsupported Position Mask (FVF := 0x%.08X dwPos := 0x%.08X)", dwCurFVF, dwPos);
|
||||
break;
|
||||
}
|
||||
|
||||
if (dwCurFVF & D3DFVF_NORMAL) {
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Normal.x;
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Normal.y;
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Normal.z;
|
||||
EmuLog(LOG_LEVEL::DEBUG, "IVB Normal := {%f, %f, %f}", g_InlineVertexBuffer_Table[v].Normal.x, g_InlineVertexBuffer_Table[v].Normal.y, g_InlineVertexBuffer_Table[v].Normal.z);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 // TODO : Was this supported on Xbox from some point in time (pun intended)?
|
||||
if (dwCurFVF & D3DFVF_PSIZE) {
|
||||
*(DWORD*)pVertexBufferData++ = g_InlineVertexBuffer_Table[v].PointSize;
|
||||
EmuLog(LOG_LEVEL::DEBUG, "IVB PointSize := 0x%.08X", g_InlineVertexBuffer_Table[v].PointSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dwCurFVF & D3DFVF_DIFFUSE) {
|
||||
*(DWORD*)pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Diffuse;
|
||||
EmuLog(LOG_LEVEL::DEBUG, "IVB Diffuse := 0x%.08X", g_InlineVertexBuffer_Table[v].Diffuse);
|
||||
}
|
||||
|
||||
if (dwCurFVF & D3DFVF_SPECULAR) {
|
||||
*(DWORD*)pVertexBufferData++ = g_InlineVertexBuffer_Table[v].Specular;
|
||||
EmuLog(LOG_LEVEL::DEBUG, "IVB Specular := 0x%.08X", g_InlineVertexBuffer_Table[v].Specular);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < dwTexN; i++) {
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].TexCoord[i].x;
|
||||
if (TexSize[i] >= 2) {
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].TexCoord[i].y;
|
||||
if (TexSize[i] >= 3) {
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].TexCoord[i].z;
|
||||
if (TexSize[i] >= 4) {
|
||||
*pVertexBufferData++ = g_InlineVertexBuffer_Table[v].TexCoord[i].w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (g_bPrintfOn) {
|
||||
switch (TexSize[i]) {
|
||||
case 1: EmuLog(LOG_LEVEL::DEBUG, "IVB TexCoord%d := {%f}", i + 1, g_InlineVertexBuffer_Table[v].TexCoord[i].x); break;
|
||||
case 2: EmuLog(LOG_LEVEL::DEBUG, "IVB TexCoord%d := {%f, %f}", i + 1, g_InlineVertexBuffer_Table[v].TexCoord[i].x, g_InlineVertexBuffer_Table[v].TexCoord[i].y); break;
|
||||
case 3: EmuLog(LOG_LEVEL::DEBUG, "IVB TexCoord%d := {%f, %f, %f}", i + 1, g_InlineVertexBuffer_Table[v].TexCoord[i].x, g_InlineVertexBuffer_Table[v].TexCoord[i].y, g_InlineVertexBuffer_Table[v].TexCoord[i].z); break;
|
||||
case 4: EmuLog(LOG_LEVEL::DEBUG, "IVB TexCoord%d := {%f, %f, %f, %f}", i + 1, g_InlineVertexBuffer_Table[v].TexCoord[i].x, g_InlineVertexBuffer_Table[v].TexCoord[i].y, g_InlineVertexBuffer_Table[v].TexCoord[i].z, g_InlineVertexBuffer_Table[v].TexCoord[i].w); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (v == 0) {
|
||||
unsigned int VertexBufferUsage = (uintptr_t)pVertexBufferData - (uintptr_t)g_InlineVertexBuffer_pData;
|
||||
if (VertexBufferUsage != uiStride) {
|
||||
CxbxKrnlCleanup("EmuFlushIVB uses wrong stride!");
|
||||
// For each register that ever got written, copy the data over from
|
||||
// g_InlineVertexBuffer_Table to pVertexBufferData, but adjacent
|
||||
// to eachother. This, so that host accepts this as a vertex declaration.
|
||||
// Note, that if we figure out how to draw using vertex buffers that
|
||||
// contain gaps, the following copy is no longer needed, and we could
|
||||
// draw straight from g_InlineVertexBuffer_Table instead!
|
||||
uint8_t* pVertexBufferData = (uint8_t*)g_InlineVertexBuffer_pData;
|
||||
for (unsigned int v = 0; v < g_InlineVertexBuffer_TableOffset; v++) {
|
||||
auto vertex_ptr = (uint8_t*)&(g_InlineVertexBuffer_Table[v]);
|
||||
for (unsigned int reg = 0; reg < X_VSH_MAX_ATTRIBUTES; reg++) {
|
||||
if (g_InlineVertexBuffer_WrittenRegisters & (1 << reg)) {
|
||||
auto source = vertex_ptr + OffsetPerRegister[reg];
|
||||
auto size = SizePerRegister[reg];
|
||||
// Note, that g_InlineVertexBuffer_AttributeFormat is declared with
|
||||
// data types (in g_InlineVertexBuffer_Table ) that are host-compatible,
|
||||
// so we can do a straight copy here, there's no conversion needed :
|
||||
memcpy(pVertexBufferData, source, size);
|
||||
pVertexBufferData += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Arrange for g_InlineVertexBuffer_AttributeFormat to be returned in CxbxGetVertexDeclaration,
|
||||
// so that our above composed declaration will be used for the next draw :
|
||||
g_InlineVertexBuffer_DeclarationOverride = true;
|
||||
// Note, that g_Xbox_VertexShader_IsFixedFunction should be left untouched,
|
||||
// because except for the declaration override, the Xbox shader (either FVF
|
||||
// or a program, or even passthrough shaders) should still be in effect!
|
||||
|
||||
CxbxUpdateNativeD3DResources();
|
||||
|
||||
CxbxDrawContext DrawContext = {};
|
||||
|
||||
DrawContext.XboxPrimitiveType = g_InlineVertexBuffer_PrimitiveType;
|
||||
|
@ -1025,20 +858,178 @@ void EmuFlushIVB()
|
|||
DrawContext.pXboxVertexStreamZeroData = g_InlineVertexBuffer_pData;
|
||||
DrawContext.uiXboxVertexStreamZeroStride = uiStride;
|
||||
|
||||
HRESULT hRet;
|
||||
|
||||
if (bFVF) {
|
||||
g_pD3DDevice->SetVertexShader(nullptr);
|
||||
hRet = g_pD3DDevice->SetFVF(dwCurFVF);
|
||||
//DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexShader");
|
||||
}
|
||||
|
||||
CxbxDrawPrimitiveUP(DrawContext);
|
||||
if (bFVF) {
|
||||
hRet = g_pD3DDevice->SetFVF(g_Xbox_VertexShader_Handle);
|
||||
//DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexShader");
|
||||
|
||||
// Now that we've drawn, stop our override in CxbxGetVertexDeclaration :
|
||||
g_InlineVertexBuffer_DeclarationOverride = false;
|
||||
|
||||
// TODO: Should technically clean this up at some point..but on XP doesnt matter much
|
||||
// g_VMManager.Deallocate((VAddr)g_InlineVertexBuffer_pData);
|
||||
// g_VMManager.Deallocate((VAddr)g_InlineVertexBuffer_Table);
|
||||
}
|
||||
|
||||
void CxbxImpl_SetVertexData4f(int Register, FLOAT a, FLOAT b, FLOAT c, FLOAT d)
|
||||
{
|
||||
using namespace xbox;
|
||||
|
||||
HRESULT hRet = D3D_OK;
|
||||
|
||||
// Always update our attribute storage with the most recently set register value
|
||||
CxbxSetVertexAttribute(Register, a, b, c, d);
|
||||
|
||||
// Grow g_InlineVertexBuffer_Table to contain at least current, and a potentially next vertex
|
||||
if (g_InlineVertexBuffer_TableLength <= g_InlineVertexBuffer_TableOffset + 1) {
|
||||
UINT InlineVertexBuffer_TableLength_Original = g_InlineVertexBuffer_TableLength;
|
||||
if (g_InlineVertexBuffer_TableLength == 0) {
|
||||
g_InlineVertexBuffer_TableLength = PAGE_SIZE / sizeof(D3DIVB);
|
||||
} else {
|
||||
g_InlineVertexBuffer_TableLength *= 2;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < (g_InlineVertexBuffer_TableLength - InlineVertexBuffer_TableLength_Original); ++i) {
|
||||
g_InlineVertexBuffer_Table.emplace_back();
|
||||
}
|
||||
|
||||
EmuLog(LOG_LEVEL::DEBUG, "Expanded g_InlineVertexBuffer_Table to %u entries", g_InlineVertexBuffer_TableLength);
|
||||
|
||||
// Sanity check: ensure that g_InlineVertexBuffer_Table is not growing indefinetly. This can happen if D3DDevice_Begin and D3DDevice_End
|
||||
// are not patched, since they both reset g_InlineVertexBuffer_TableOffset back to zero, thus preventing further growth
|
||||
if (g_InlineVertexBuffer_TableLength > 50000) {
|
||||
LOG_TEST_CASE("g_InlineVertexBuffer_TableLength > 50000! This probably means that g_InlineVertexBuffer_Table is growing indefinitely.");
|
||||
}
|
||||
}
|
||||
|
||||
// Is this the initial call after D3DDevice_Begin() ?
|
||||
if (g_InlineVertexBuffer_WrittenRegisters == 0) {
|
||||
// Read starting values for all inline vertex attributes from HLE NV2A pgraph (converting them to required types) :
|
||||
g_InlineVertexBuffer_Table[0].Position = D3DXVECTOR3(HLE_get_NV2A_vertex_attribute_value_pointer(X_D3DVSDE_POSITION));
|
||||
g_InlineVertexBuffer_Table[0].Rhw = HLE_get_NV2A_vertex_attribute_value_pointer(X_D3DVSDE_POSITION)[3];
|
||||
g_InlineVertexBuffer_Table[0].Blend[0] = HLE_get_NV2A_vertex_attribute_value_pointer(X_D3DVSDE_BLENDWEIGHT)[0];
|
||||
g_InlineVertexBuffer_Table[0].Blend[1] = HLE_get_NV2A_vertex_attribute_value_pointer(X_D3DVSDE_BLENDWEIGHT)[1];
|
||||
g_InlineVertexBuffer_Table[0].Blend[2] = HLE_get_NV2A_vertex_attribute_value_pointer(X_D3DVSDE_BLENDWEIGHT)[2];
|
||||
g_InlineVertexBuffer_Table[0].Blend[3] = HLE_get_NV2A_vertex_attribute_value_pointer(X_D3DVSDE_BLENDWEIGHT)[3];
|
||||
g_InlineVertexBuffer_Table[0].Normal = D3DXVECTOR3(HLE_get_NV2A_vertex_attribute_value_pointer(X_D3DVSDE_NORMAL));
|
||||
g_InlineVertexBuffer_Table[0].Diffuse = Float4ToDWORD(HLE_get_NV2A_vertex_attribute_value_pointer(X_D3DVSDE_DIFFUSE));
|
||||
g_InlineVertexBuffer_Table[0].Specular = Float4ToDWORD(HLE_get_NV2A_vertex_attribute_value_pointer(X_D3DVSDE_SPECULAR));
|
||||
g_InlineVertexBuffer_Table[0].Fog = HLE_get_NV2A_vertex_attribute_value_pointer(X_D3DVSDE_FOG)[0];
|
||||
g_InlineVertexBuffer_Table[0].PointSize = HLE_get_NV2A_vertex_attribute_value_pointer(X_D3DVSDE_POINTSIZE)[0];
|
||||
g_InlineVertexBuffer_Table[0].BackDiffuse = Float4ToDWORD(HLE_get_NV2A_vertex_attribute_value_pointer(X_D3DVSDE_BACKDIFFUSE));
|
||||
g_InlineVertexBuffer_Table[0].BackSpecular = Float4ToDWORD(HLE_get_NV2A_vertex_attribute_value_pointer(X_D3DVSDE_BACKSPECULAR));
|
||||
g_InlineVertexBuffer_Table[0].TexCoord[0] = D3DXVECTOR4(HLE_get_NV2A_vertex_attribute_value_pointer(X_D3DVSDE_TEXCOORD0));
|
||||
g_InlineVertexBuffer_Table[0].TexCoord[1] = D3DXVECTOR4(HLE_get_NV2A_vertex_attribute_value_pointer(X_D3DVSDE_TEXCOORD1));
|
||||
g_InlineVertexBuffer_Table[0].TexCoord[2] = D3DXVECTOR4(HLE_get_NV2A_vertex_attribute_value_pointer(X_D3DVSDE_TEXCOORD2));
|
||||
g_InlineVertexBuffer_Table[0].TexCoord[3] = D3DXVECTOR4(HLE_get_NV2A_vertex_attribute_value_pointer(X_D3DVSDE_TEXCOORD3));
|
||||
g_InlineVertexBuffer_Table[0].Reg13Up[0] = D3DXVECTOR4(HLE_get_NV2A_vertex_attribute_value_pointer(13));
|
||||
g_InlineVertexBuffer_Table[0].Reg13Up[1] = D3DXVECTOR4(HLE_get_NV2A_vertex_attribute_value_pointer(14));
|
||||
g_InlineVertexBuffer_Table[0].Reg13Up[2] = D3DXVECTOR4(HLE_get_NV2A_vertex_attribute_value_pointer(15));
|
||||
// Note : Because all members are assigned an initial value, there's no need for a clearing constructor for _D3DIVB!
|
||||
}
|
||||
|
||||
if (Register == X_D3DVSDE_VERTEX)
|
||||
g_InlineVertexBuffer_WrittenRegisters |= (1 << X_D3DVSDE_POSITION);
|
||||
else if (Register < 16)
|
||||
g_InlineVertexBuffer_WrittenRegisters |= (1 << Register);
|
||||
|
||||
unsigned o = g_InlineVertexBuffer_TableOffset;
|
||||
|
||||
switch (Register)
|
||||
{
|
||||
case X_D3DVSDE_VERTEX:
|
||||
case X_D3DVSDE_POSITION:
|
||||
{
|
||||
// Note : Setting position signals completion of a vertex
|
||||
g_InlineVertexBuffer_Table[o].Position.x = a;
|
||||
g_InlineVertexBuffer_Table[o].Position.y = b;
|
||||
g_InlineVertexBuffer_Table[o].Position.z = c;
|
||||
g_InlineVertexBuffer_Table[o].Rhw = d;
|
||||
// Start a new vertex
|
||||
g_InlineVertexBuffer_TableOffset++;
|
||||
// Copy all attributes of the prior vertex to the new one, to simulate persistent attribute values
|
||||
g_InlineVertexBuffer_Table[g_InlineVertexBuffer_TableOffset] = g_InlineVertexBuffer_Table[o];
|
||||
break;
|
||||
}
|
||||
|
||||
case X_D3DVSDE_BLENDWEIGHT:
|
||||
{
|
||||
g_InlineVertexBuffer_Table[o].Blend[0] = a;
|
||||
g_InlineVertexBuffer_Table[o].Blend[1] = b;
|
||||
g_InlineVertexBuffer_Table[o].Blend[2] = c;
|
||||
g_InlineVertexBuffer_Table[o].Blend[3] = d;
|
||||
break;
|
||||
}
|
||||
|
||||
case X_D3DVSDE_NORMAL:
|
||||
{
|
||||
g_InlineVertexBuffer_Table[o].Normal.x = a;
|
||||
g_InlineVertexBuffer_Table[o].Normal.y = b;
|
||||
g_InlineVertexBuffer_Table[o].Normal.z = c;
|
||||
break;
|
||||
}
|
||||
|
||||
case X_D3DVSDE_DIFFUSE:
|
||||
{
|
||||
g_InlineVertexBuffer_Table[o].Diffuse = D3DCOLOR_COLORVALUE(a, b, c, d);
|
||||
break;
|
||||
}
|
||||
|
||||
case X_D3DVSDE_SPECULAR:
|
||||
{
|
||||
g_InlineVertexBuffer_Table[o].Specular = D3DCOLOR_COLORVALUE(a, b, c, d);
|
||||
break;
|
||||
}
|
||||
|
||||
case X_D3DVSDE_FOG: // Xbox extension
|
||||
{
|
||||
g_InlineVertexBuffer_Table[o].Fog = a; // TODO : What about the other (b, c and d) arguments?
|
||||
break;
|
||||
}
|
||||
|
||||
case X_D3DVSDE_POINTSIZE:
|
||||
{
|
||||
g_InlineVertexBuffer_Table[o].PointSize = a; // TODO : What about the other (b, c and d) arguments?
|
||||
break;
|
||||
}
|
||||
|
||||
case X_D3DVSDE_BACKDIFFUSE: // Xbox extension
|
||||
{
|
||||
g_InlineVertexBuffer_Table[o].BackDiffuse = D3DCOLOR_COLORVALUE(a, b, c, d);
|
||||
break;
|
||||
}
|
||||
|
||||
case X_D3DVSDE_BACKSPECULAR: // Xbox extension
|
||||
{
|
||||
g_InlineVertexBuffer_Table[o].BackSpecular = D3DCOLOR_COLORVALUE(a, b, c, d);
|
||||
break;
|
||||
}
|
||||
|
||||
case X_D3DVSDE_TEXCOORD0:
|
||||
case X_D3DVSDE_TEXCOORD1:
|
||||
case X_D3DVSDE_TEXCOORD2:
|
||||
case X_D3DVSDE_TEXCOORD3:
|
||||
{
|
||||
unsigned i = Register - X_D3DVSDE_TEXCOORD0;
|
||||
g_InlineVertexBuffer_Table[o].TexCoord[i].x = a;
|
||||
g_InlineVertexBuffer_Table[o].TexCoord[i].y = b;
|
||||
g_InlineVertexBuffer_Table[o].TexCoord[i].z = c;
|
||||
g_InlineVertexBuffer_Table[o].TexCoord[i].w = d;
|
||||
break;
|
||||
}
|
||||
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
{
|
||||
unsigned i = Register - 13;
|
||||
g_InlineVertexBuffer_Table[o].Reg13Up[i].x = a;
|
||||
g_InlineVertexBuffer_Table[o].Reg13Up[i].y = b;
|
||||
g_InlineVertexBuffer_Table[o].Reg13Up[i].z = c;
|
||||
g_InlineVertexBuffer_Table[o].Reg13Up[i].w = d;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
EmuLog(LOG_LEVEL::WARNING, "Unknown IVB Register : %d", Register);
|
||||
}
|
||||
g_InlineVertexBuffer_TableOffset = 0; // Might not be needed (also cleared in D3DDevice_Begin)
|
||||
}
|
||||
|
||||
void CxbxImpl_SetStreamSource(UINT StreamNumber, xbox::X_D3DVertexBuffer* pStreamData, UINT Stride)
|
||||
|
|
|
@ -56,7 +56,8 @@ class CxbxPatchedStream
|
|||
public:
|
||||
CxbxPatchedStream();
|
||||
~CxbxPatchedStream();
|
||||
void Activate(CxbxDrawContext *pDrawContext, UINT uiStream) const;
|
||||
void Clear();
|
||||
void Activate(CxbxDrawContext *pDrawContext, UINT HostStreamNumber) const;
|
||||
bool isValid = false;
|
||||
xbox::X_D3DPRIMITIVETYPE XboxPrimitiveType = xbox::X_D3DPT_NONE;
|
||||
PVOID pCachedXboxVertexData = xbox::zeroptr;
|
||||
|
@ -99,39 +100,44 @@ class CxbxVertexBufferConverter
|
|||
void ConvertStream(CxbxDrawContext *pPatchDesc, UINT uiStream);
|
||||
};
|
||||
|
||||
// inline vertex buffer emulation
|
||||
// Inline vertex buffer emulation
|
||||
extern xbox::X_D3DPRIMITIVETYPE g_InlineVertexBuffer_PrimitiveType;
|
||||
extern DWORD g_InlineVertexBuffer_FVF;
|
||||
|
||||
struct _D3DIVB
|
||||
typedef struct _D3DIVB
|
||||
{
|
||||
D3DXVECTOR3 Position; // X_D3DVSDE_POSITION (*) > D3DFVF_XYZ / D3DFVF_XYZRHW
|
||||
FLOAT Rhw; // X_D3DVSDE_VERTEX (*) > D3DFVF_XYZ / D3DFVF_XYZRHW
|
||||
FLOAT Blend[4]; // X_D3DVSDE_BLENDWEIGHT > D3DFVF_XYZB1 (and 3 more up to D3DFVF_XYZB4)
|
||||
FLOAT Rhw; // X_D3DVSDE_VERTEX (*) > D3DFVF_XYZ / D3DFVF_XYZRHW
|
||||
FLOAT Blend[4]; // X_D3DVSDE_BLENDWEIGHT > D3DFVF_XYZB1 (and 3 more up to D3DFVF_XYZB4)
|
||||
D3DXVECTOR3 Normal; // X_D3DVSDE_NORMAL > D3DFVF_NORMAL
|
||||
D3DCOLOR Diffuse; // X_D3DVSDE_DIFFUSE > D3DFVF_DIFFUSE
|
||||
D3DCOLOR Specular; // X_D3DVSDE_SPECULAR > D3DFVF_SPECULAR
|
||||
FLOAT Fog; // X_D3DVSDE_FOG > D3DFVF_FOG unavailable; TODO : How to handle?
|
||||
D3DCOLOR BackDiffuse; // X_D3DVSDE_BACKDIFFUSE > D3DFVF_BACKDIFFUSE unavailable; TODO : How to handle?
|
||||
D3DCOLOR BackSpecular; // X_D3DVSDE_BACKSPECULAR > D3DFVF_BACKSPECULAR unavailable; TODO : How to handle?
|
||||
D3DXVECTOR4 TexCoord[4]; // X_D3DVSDE_TEXCOORD0 > D3DFVF_TEX1 (and 4 more up to D3DFVF_TEX4)
|
||||
|
||||
D3DCOLOR Diffuse; // X_D3DVSDE_DIFFUSE > D3DFVF_DIFFUSE
|
||||
D3DCOLOR Specular; // X_D3DVSDE_SPECULAR > D3DFVF_SPECULAR
|
||||
FLOAT Fog; // X_D3DVSDE_FOG > D3DFVF_FOG unavailable; TODO : How to handle?
|
||||
FLOAT PointSize; // X_D3DVSDE_POINTSIZE > D3DFVF_POINTSIZE unavailable; TODO : How to handle?
|
||||
D3DCOLOR BackDiffuse; // X_D3DVSDE_BACKDIFFUSE > D3DFVF_BACKDIFFUSE unavailable; TODO : How to handle?
|
||||
D3DCOLOR BackSpecular; // X_D3DVSDE_BACKSPECULAR > D3DFVF_BACKSPECULAR unavailable; TODO : How to handle?
|
||||
D3DXVECTOR4 TexCoord[4]; // X_D3DVSDE_TEXCOORD0 > D3DFVF_TEX1, (and 3 more up to D3DFVF_TEX4)
|
||||
D3DXVECTOR4 Reg13Up[3];
|
||||
// (*) X_D3DVSDE_POSITION and X_D3DVSDE_VERTEX both set Position, but Rhw seems optional,
|
||||
// hence, selection for D3DFVF_XYZ or D3DFVF_XYZRHW is rather fuzzy. We DO know that once
|
||||
// D3DFVF_NORMAL is given, D3DFVF_XYZRHW is forbidden (see D3DDevice_SetVertexData4f)
|
||||
|
||||
_D3DIVB();
|
||||
struct _D3DIVB &operator=(const struct _D3DIVB &Val);
|
||||
};
|
||||
|
||||
extern std::vector<_D3DIVB> g_InlineVertexBuffer_Table;
|
||||
} D3DIVB;
|
||||
|
||||
extern std::vector<D3DIVB> g_InlineVertexBuffer_Table;
|
||||
extern UINT g_InlineVertexBuffer_TableLength;
|
||||
extern UINT g_InlineVertexBuffer_TableOffset;
|
||||
|
||||
extern void EmuFlushIVB();
|
||||
|
||||
extern void EmuUpdateActiveTexture();
|
||||
|
||||
extern void CxbxSetVertexAttribute(int Register, FLOAT a, FLOAT b, FLOAT c, FLOAT d);
|
||||
|
||||
extern void CxbxImpl_Begin(xbox::X_D3DPRIMITIVETYPE PrimitiveType);
|
||||
extern void CxbxImpl_End();
|
||||
extern void CxbxImpl_SetStreamSource(UINT StreamNumber, xbox::X_D3DVertexBuffer* pStreamData, UINT Stride);
|
||||
extern void CxbxImpl_SetVertexData4f(int Register, FLOAT a, FLOAT b, FLOAT c, FLOAT d);
|
||||
|
||||
extern DWORD g_dwPrimPerFrame;
|
||||
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -40,9 +40,10 @@
|
|||
|
||||
typedef struct _CxbxVertexShaderStreamElement
|
||||
{
|
||||
UINT XboxType; // The stream element data types (xbox)
|
||||
UINT XboxByteSize; // The stream element data sizes (xbox)
|
||||
UINT HostByteSize; // The stream element data sizes (pc)
|
||||
UINT XboxType; // The stream element data type (xbox)
|
||||
UINT XboxByteSize; // The stream element data size (xbox)
|
||||
BYTE HostDataType; // The stream element data type (pc)
|
||||
UINT HostByteSize; // The stream element data size (pc)
|
||||
}
|
||||
CxbxVertexShaderStreamElement;
|
||||
|
||||
|
@ -60,53 +61,25 @@ CxbxVertexShaderStreamElement;
|
|||
typedef struct _CxbxVertexShaderStreamInfo
|
||||
{
|
||||
BOOL NeedPatch; // This is to know whether it's data which must be patched
|
||||
BOOL DeclPosition;
|
||||
WORD HostVertexStride;
|
||||
DWORD NumberOfVertexElements; // Number of the stream data types
|
||||
WORD CurrentStreamNumber;
|
||||
CxbxVertexShaderStreamElement VertexElements[X_VSH_MAX_ATTRIBUTES + 16]; // TODO : Why 16 extra host additions?)
|
||||
WORD XboxStreamIndex;
|
||||
CxbxVertexShaderStreamElement VertexElements[X_VSH_MAX_ATTRIBUTES];
|
||||
}
|
||||
CxbxVertexShaderStreamInfo;
|
||||
|
||||
typedef uint64_t VertexDeclarationKey;
|
||||
|
||||
typedef struct _CxbxVertexDeclaration
|
||||
{
|
||||
CxbxVertexShaderStreamInfo VertexStreams[X_VSH_MAX_STREAMS];
|
||||
VertexDeclarationKey Key;
|
||||
CxbxVertexShaderStreamInfo VertexStreams[X_VSH_MAX_STREAMS]; // Note : VertexStreams is indexed by a counter, NOT StreamIndex!
|
||||
IDirect3DVertexDeclaration* pHostVertexDeclaration;
|
||||
DWORD* pXboxDeclarationCopy;
|
||||
DWORD XboxDeclarationCount; // Xbox's number of DWORD-sized X_D3DVSD* tokens
|
||||
UINT NumberOfVertexStreams; // The number of streams the vertex shader uses
|
||||
UINT NumberOfVertexStreams; // The number of streams the vertex shader uses
|
||||
bool vRegisterInDeclaration[X_VSH_MAX_ATTRIBUTES];
|
||||
}
|
||||
CxbxVertexDeclaration;
|
||||
|
||||
|
||||
typedef struct _CxbxVertexShader
|
||||
{
|
||||
// These are the parameters given by the XBE,
|
||||
// we save them to be able to return them when necessary.
|
||||
DWORD XboxFunctionSize;
|
||||
DWORD* pXboxFunctionCopy;
|
||||
UINT XboxNrAddressSlots;
|
||||
DWORD XboxVertexShaderType;
|
||||
// DWORD XboxStatus; // Used by VshHandleIsValidShader()
|
||||
|
||||
// The resulting host variables
|
||||
uint64_t VertexShaderKey;
|
||||
|
||||
// Needed for dynamic stream patching
|
||||
CxbxVertexDeclaration Declaration;
|
||||
}
|
||||
CxbxVertexShader;
|
||||
|
||||
// recompile xbox vertex shader declaration
|
||||
extern D3DVERTEXELEMENT *EmuRecompileVshDeclaration
|
||||
(
|
||||
DWORD *pXboxDeclaration,
|
||||
bool bIsFixedFunction,
|
||||
DWORD *pXboxDeclarationCount,
|
||||
CxbxVertexDeclaration *pCxbxVertexDeclaration
|
||||
);
|
||||
|
||||
// Intermediate vertex shader structures
|
||||
|
||||
enum VSH_OREG_NAME {
|
||||
|
@ -224,25 +197,21 @@ extern void EmuParseVshFunction
|
|||
IntermediateVertexShader* pShader
|
||||
);
|
||||
|
||||
extern void FreeVertexDynamicPatch(CxbxVertexShader *pVertexShader);
|
||||
|
||||
// Checks for failed vertex shaders, and shaders that would need patching
|
||||
extern boolean IsValidCurrentShader(void);
|
||||
|
||||
inline boolean VshHandleIsVertexShader(DWORD Handle) { return (Handle & X_D3DFVF_RESERVED0) ? TRUE : FALSE; }
|
||||
inline boolean VshHandleIsFVF(DWORD Handle) { return !VshHandleIsVertexShader(Handle); }
|
||||
inline xbox::X_D3DVertexShader *VshHandleToXboxVertexShader(DWORD Handle) { return (xbox::X_D3DVertexShader *)(Handle & ~X_D3DFVF_RESERVED0);}
|
||||
|
||||
extern CxbxVertexShader* GetCxbxVertexShader(DWORD XboxVertexShaderHandle);
|
||||
extern bool g_Xbox_VertexShader_IsFixedFunction;
|
||||
|
||||
extern CxbxVertexDeclaration* CxbxGetVertexDeclaration();
|
||||
extern xbox::X_STREAMINPUT& GetXboxVertexStreamInput(unsigned XboxStreamNumber);
|
||||
|
||||
extern void CxbxImpl_SetScreenSpaceOffset(float x, float y);
|
||||
extern void CxbxImpl_LoadVertexShaderProgram(CONST DWORD* pFunction, DWORD Address);
|
||||
extern void CxbxImpl_LoadVertexShader(DWORD Handle, DWORD Address);
|
||||
extern void CxbxImpl_SetVertexShader(DWORD Handle);
|
||||
extern void CxbxImpl_SelectVertexShaderDirect(xbox::X_VERTEXATTRIBUTEFORMAT* pVAF, DWORD Address);
|
||||
extern void CxbxImpl_SelectVertexShader(DWORD Handle, DWORD Address);
|
||||
extern void CxbxImpl_SetVertexShaderInput(DWORD Handle, UINT StreamCount, xbox::X_STREAMINPUT* pStreamInputs);
|
||||
extern void CxbxImpl_SetVertexShaderConstant(INT Register, PVOID pConstantData, DWORD ConstantCount);
|
||||
extern HRESULT CxbxImpl_CreateVertexShader(CONST DWORD *pDeclaration, CONST DWORD *pFunction, DWORD *pHandle, DWORD Usage);
|
||||
extern void CxbxImpl_DeleteVertexShader(DWORD Handle);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -64,7 +64,7 @@ std::map<const std::string, const xbox_patch_t> g_PatchTable = {
|
|||
PATCH_ENTRY("D3DDevice_BlockUntilVerticalBlank", xbox::EMUPATCH(D3DDevice_BlockUntilVerticalBlank), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_Clear", xbox::EMUPATCH(D3DDevice_Clear), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_CopyRects", xbox::EMUPATCH(D3DDevice_CopyRects), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_CreateVertexShader", xbox::EMUPATCH(D3DDevice_CreateVertexShader), PATCH_HLE_D3D),
|
||||
// PATCH_ENTRY("D3DDevice_CreateVertexShader", xbox::EMUPATCH(D3DDevice_CreateVertexShader), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_DeleteVertexShader", xbox::EMUPATCH(D3DDevice_DeleteVertexShader), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_DeleteVertexShader_0", xbox::EMUPATCH(D3DDevice_DeleteVertexShader_0), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_DrawIndexedVertices", xbox::EMUPATCH(D3DDevice_DrawIndexedVertices), PATCH_HLE_D3D),
|
||||
|
@ -95,7 +95,7 @@ std::map<const std::string, const xbox_patch_t> g_PatchTable = {
|
|||
PATCH_ENTRY("D3DDevice_GetVertexShaderConstant", xbox::EMUPATCH(D3DDevice_GetVertexShaderConstant), PATCH_HLE_D3D),
|
||||
//PATCH_ENTRY("D3DDevice_GetVertexShaderDeclaration", xbox::EMUPATCH(D3DDevice_GetVertexShaderDeclaration), PATCH_HLE_D3D),
|
||||
//PATCH_ENTRY("D3DDevice_GetVertexShaderFunction", xbox::EMUPATCH(D3DDevice_GetVertexShaderFunction), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_GetVertexShaderInput", xbox::EMUPATCH(D3DDevice_GetVertexShaderInput), PATCH_HLE_D3D),
|
||||
//PATCH_ENTRY("D3DDevice_GetVertexShaderInput", xbox::EMUPATCH(D3DDevice_GetVertexShaderInput), PATCH_HLE_D3D),
|
||||
//PATCH_ENTRY("D3DDevice_GetVertexShaderSize", xbox::EMUPATCH(D3DDevice_GetVertexShaderSize), PATCH_HLE_D3D),
|
||||
//PATCH_ENTRY("D3DDevice_GetVertexShaderType", xbox::EMUPATCH(D3DDevice_GetVertexShaderType), PATCH_HLE_D3D),
|
||||
//PATCH_ENTRY("D3DDevice_GetViewportOffsetAndScale", xbox::EMUPATCH(D3DDevice_GetViewportOffsetAndScale), PATCH_HLE_D3D),
|
||||
|
@ -117,7 +117,7 @@ std::map<const std::string, const xbox_patch_t> g_PatchTable = {
|
|||
PATCH_ENTRY("D3DDevice_RunPushBuffer", xbox::EMUPATCH(D3DDevice_RunPushBuffer), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_RunVertexStateShader", xbox::EMUPATCH(D3DDevice_RunVertexStateShader), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_SelectVertexShader", xbox::EMUPATCH(D3DDevice_SelectVertexShader), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_SelectVertexShaderDirect", xbox::EMUPATCH(D3DDevice_SelectVertexShaderDirect), PATCH_HLE_D3D),
|
||||
//PATCH_ENTRY("D3DDevice_SelectVertexShaderDirect", xbox::EMUPATCH(D3DDevice_SelectVertexShaderDirect), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_SelectVertexShader_0", xbox::EMUPATCH(D3DDevice_SelectVertexShader_0), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_SelectVertexShader_4", xbox::EMUPATCH(D3DDevice_SelectVertexShader_4), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_SetBackBufferScale", xbox::EMUPATCH(D3DDevice_SetBackBufferScale), PATCH_HLE_D3D),
|
||||
|
@ -173,7 +173,7 @@ std::map<const std::string, const xbox_patch_t> g_PatchTable = {
|
|||
PATCH_ENTRY("D3DDevice_SetVertexShaderConstantNotInlineFast", xbox::EMUPATCH(D3DDevice_SetVertexShaderConstantNotInlineFast), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_SetVertexShaderConstant_8", xbox::EMUPATCH(D3DDevice_SetVertexShaderConstant_8), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_SetVertexShaderInput", xbox::EMUPATCH(D3DDevice_SetVertexShaderInput), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_SetVertexShaderInputDirect", xbox::EMUPATCH(D3DDevice_SetVertexShaderInputDirect), PATCH_HLE_D3D),
|
||||
//PATCH_ENTRY("D3DDevice_SetVertexShaderInputDirect", xbox::EMUPATCH(D3DDevice_SetVertexShaderInputDirect), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_SetVerticalBlankCallback", xbox::EMUPATCH(D3DDevice_SetVerticalBlankCallback), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_SetViewport", xbox::EMUPATCH(D3DDevice_SetViewport), PATCH_HLE_D3D),
|
||||
PATCH_ENTRY("D3DDevice_Swap", xbox::EMUPATCH(D3DDevice_Swap), PATCH_HLE_D3D),
|
||||
|
|
|
@ -441,22 +441,78 @@ static uint64_t fnv_hash(const uint8_t *data, size_t len);
|
|||
static uint64_t fast_hash(const uint8_t *data, size_t len, unsigned int samples);
|
||||
|
||||
/* PGRAPH - accelerated 2d/3d drawing engine */
|
||||
|
||||
static uint32_t pgraph_rdi_read(PGRAPHState *pg,
|
||||
unsigned int select, unsigned int address)
|
||||
{
|
||||
uint32_t r = 0;
|
||||
switch(select) {
|
||||
case RDI_INDEX_VTX_CONSTANTS0:
|
||||
case RDI_INDEX_VTX_CONSTANTS1:
|
||||
assert((address / 4) < NV2A_VERTEXSHADER_CONSTANTS);
|
||||
r = pg->vsh_constants[address / 4][3 - address % 4];
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "nv2a: unknown rdi read select 0x%x address 0x%x\n",
|
||||
select, address);
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static void pgraph_rdi_write(PGRAPHState *pg,
|
||||
unsigned int select, unsigned int address,
|
||||
uint32_t val)
|
||||
{
|
||||
switch(select) {
|
||||
case RDI_INDEX_VTX_CONSTANTS0:
|
||||
case RDI_INDEX_VTX_CONSTANTS1:
|
||||
assert(false); /* Untested */
|
||||
assert((address / 4) < NV2A_VERTEXSHADER_CONSTANTS);
|
||||
pg->vsh_constants_dirty[address / 4] |=
|
||||
(val != pg->vsh_constants[address / 4][3 - address % 4]);
|
||||
pg->vsh_constants[address / 4][3 - address % 4] = val;
|
||||
break;
|
||||
default:
|
||||
NV2A_DPRINTF("unknown rdi write select 0x%x, address 0x%x, val 0x%08x\n",
|
||||
select, address, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEVICE_READ32(PGRAPH)
|
||||
{
|
||||
qemu_mutex_lock(&d->pgraph.pgraph_lock);
|
||||
|
||||
PGRAPHState *pg = &d->pgraph;
|
||||
DEVICE_READ32_SWITCH() {
|
||||
case NV_PGRAPH_INTR:
|
||||
result = d->pgraph.pending_interrupts;
|
||||
result = pg->pending_interrupts;
|
||||
break;
|
||||
case NV_PGRAPH_INTR_EN:
|
||||
result = d->pgraph.enabled_interrupts;
|
||||
result = pg->enabled_interrupts;
|
||||
break;
|
||||
case NV_PGRAPH_RDI_DATA: {
|
||||
unsigned int select = GET_MASK(pg->regs[NV_PGRAPH_RDI_INDEX],
|
||||
NV_PGRAPH_RDI_INDEX_SELECT);
|
||||
int address = GET_MASK(pg->regs[NV_PGRAPH_RDI_INDEX],
|
||||
NV_PGRAPH_RDI_INDEX_ADDRESS);
|
||||
|
||||
result = pgraph_rdi_read(pg, select, address);
|
||||
|
||||
/* FIXME: Overflow into select? */
|
||||
assert(address < GET_MASK(NV_PGRAPH_RDI_INDEX_ADDRESS,
|
||||
NV_PGRAPH_RDI_INDEX_ADDRESS));
|
||||
SET_MASK(pg->regs[NV_PGRAPH_RDI_INDEX],
|
||||
NV_PGRAPH_RDI_INDEX_ADDRESS, address + 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DEVICE_READ32_REG(pgraph); // Was : DEBUG_READ32_UNHANDLED(PGRAPH);
|
||||
}
|
||||
|
||||
qemu_mutex_unlock(&d->pgraph.pgraph_lock);
|
||||
qemu_mutex_unlock(&pg->pgraph_lock);
|
||||
|
||||
// reg_log_read(NV_PGRAPH, addr, r);
|
||||
|
||||
|
@ -465,36 +521,53 @@ DEVICE_READ32(PGRAPH)
|
|||
|
||||
DEVICE_WRITE32(PGRAPH)
|
||||
{
|
||||
PGRAPHState *pg = &d->pgraph;
|
||||
// reg_log_write(NV_PGRAPH, addr, val);
|
||||
|
||||
qemu_mutex_lock(&d->pgraph.pgraph_lock);
|
||||
qemu_mutex_lock(&pg->pgraph_lock);
|
||||
|
||||
switch (addr) {
|
||||
case NV_PGRAPH_INTR:
|
||||
d->pgraph.pending_interrupts &= ~value;
|
||||
qemu_cond_broadcast(&d->pgraph.interrupt_cond);
|
||||
pg->pending_interrupts &= ~value;
|
||||
qemu_cond_broadcast(&pg->interrupt_cond);
|
||||
break;
|
||||
case NV_PGRAPH_INTR_EN:
|
||||
d->pgraph.enabled_interrupts = value;
|
||||
pg->enabled_interrupts = value;
|
||||
break;
|
||||
case NV_PGRAPH_INCREMENT:
|
||||
if (value & NV_PGRAPH_INCREMENT_READ_3D) {
|
||||
SET_MASK(d->pgraph.regs[NV_PGRAPH_SURFACE],
|
||||
SET_MASK(pg->regs[NV_PGRAPH_SURFACE],
|
||||
NV_PGRAPH_SURFACE_READ_3D,
|
||||
(GET_MASK(d->pgraph.regs[NV_PGRAPH_SURFACE],
|
||||
(GET_MASK(pg->regs[NV_PGRAPH_SURFACE],
|
||||
NV_PGRAPH_SURFACE_READ_3D) + 1)
|
||||
% GET_MASK(d->pgraph.regs[NV_PGRAPH_SURFACE],
|
||||
% GET_MASK(pg->regs[NV_PGRAPH_SURFACE],
|
||||
NV_PGRAPH_SURFACE_MODULO_3D));
|
||||
qemu_cond_broadcast(&d->pgraph.flip_3d);
|
||||
qemu_cond_broadcast(&pg->flip_3d);
|
||||
}
|
||||
break;
|
||||
case NV_PGRAPH_RDI_DATA: {
|
||||
unsigned int select = GET_MASK(pg->regs[NV_PGRAPH_RDI_INDEX],
|
||||
NV_PGRAPH_RDI_INDEX_SELECT);
|
||||
int address = GET_MASK(pg->regs[NV_PGRAPH_RDI_INDEX],
|
||||
NV_PGRAPH_RDI_INDEX_ADDRESS);
|
||||
|
||||
pgraph_rdi_write(pg, select, address, value);
|
||||
|
||||
/* FIXME: Overflow into select? */
|
||||
assert(address < GET_MASK(NV_PGRAPH_RDI_INDEX_ADDRESS,
|
||||
NV_PGRAPH_RDI_INDEX_ADDRESS));
|
||||
SET_MASK(pg->regs[NV_PGRAPH_RDI_INDEX],
|
||||
NV_PGRAPH_RDI_INDEX_ADDRESS, address + 1);
|
||||
break;
|
||||
}
|
||||
case NV_PGRAPH_CHANNEL_CTX_TRIGGER: {
|
||||
xbox::addr_xt context_address =
|
||||
GET_MASK(d->pgraph.regs[NV_PGRAPH_CHANNEL_CTX_POINTER], NV_PGRAPH_CHANNEL_CTX_POINTER_INST) << 4;
|
||||
GET_MASK(pg->regs[NV_PGRAPH_CHANNEL_CTX_POINTER],
|
||||
NV_PGRAPH_CHANNEL_CTX_POINTER_INST) << 4;
|
||||
|
||||
if (value & NV_PGRAPH_CHANNEL_CTX_TRIGGER_READ_IN) {
|
||||
unsigned pgraph_channel_id =
|
||||
GET_MASK(d->pgraph.regs[NV_PGRAPH_CTX_USER], NV_PGRAPH_CTX_USER_CHID);
|
||||
GET_MASK(pg->regs[NV_PGRAPH_CTX_USER], NV_PGRAPH_CTX_USER_CHID);
|
||||
|
||||
NV2A_DPRINTF("PGRAPH: read channel %d context from %" HWADDR_PRIx "\n",
|
||||
pgraph_channel_id, context_address);
|
||||
|
@ -504,7 +577,7 @@ DEVICE_WRITE32(PGRAPH)
|
|||
|
||||
NV2A_DPRINTF(" - CTX_USER = 0x%08X\n", context_user);
|
||||
|
||||
d->pgraph.regs[NV_PGRAPH_CTX_USER] = context_user;
|
||||
pg->regs[NV_PGRAPH_CTX_USER] = context_user;
|
||||
// pgraph_set_context_user(d, context_user);
|
||||
}
|
||||
if (value & NV_PGRAPH_CHANNEL_CTX_TRIGGER_WRITE_OUT) {
|
||||
|
@ -521,11 +594,11 @@ DEVICE_WRITE32(PGRAPH)
|
|||
// events
|
||||
switch (addr) {
|
||||
case NV_PGRAPH_FIFO:
|
||||
qemu_cond_broadcast(&d->pgraph.fifo_access_cond);
|
||||
qemu_cond_broadcast(&pg->fifo_access_cond);
|
||||
break;
|
||||
}
|
||||
|
||||
qemu_mutex_unlock(&d->pgraph.pgraph_lock);
|
||||
qemu_mutex_unlock(&pg->pgraph_lock);
|
||||
|
||||
DEVICE_WRITE32_END(PGRAPH);
|
||||
}
|
||||
|
@ -1407,16 +1480,20 @@ void pgraph_handle_method(NV2AState *d,
|
|||
GET_MASK(parameter, NV097_SET_SURFACE_PITCH_COLOR);
|
||||
pg->surface_zeta.pitch =
|
||||
GET_MASK(parameter, NV097_SET_SURFACE_PITCH_ZETA);
|
||||
pg->surface_color.buffer_dirty = true;
|
||||
pg->surface_zeta.buffer_dirty = true;
|
||||
break;
|
||||
case NV097_SET_SURFACE_COLOR_OFFSET:
|
||||
pgraph_update_surface(d, false, true, true);
|
||||
|
||||
pg->surface_color.offset = parameter;
|
||||
pg->surface_color.buffer_dirty = true;
|
||||
break;
|
||||
case NV097_SET_SURFACE_ZETA_OFFSET:
|
||||
pgraph_update_surface(d, false, true, true);
|
||||
|
||||
pg->surface_zeta.offset = parameter;
|
||||
pg->surface_zeta.buffer_dirty = true;
|
||||
break;
|
||||
|
||||
CASE_8(NV097_SET_COMBINER_ALPHA_ICW, 4) :
|
||||
|
@ -2596,17 +2673,12 @@ void pgraph_handle_method(NV2AState *d,
|
|||
assert(false); /* FIXME: Untested! */
|
||||
VertexAttribute *vertex_attribute = &pg->vertex_attributes[slot];
|
||||
pgraph_allocate_inline_buffer_vertices(pg, slot);
|
||||
/* FIXME: Is mapping to [-1,+1] correct? */
|
||||
vertex_attribute->inline_value[0] = ((int16_t)(parameter & 0xFFFF) * 2.0f + 1)
|
||||
/ 65535.0f;
|
||||
vertex_attribute->inline_value[1] = ((int16_t)(parameter >> 16) * 2.0f + 1)
|
||||
/ 65535.0f;
|
||||
/* FIXME: Should these really be set to 0.0 and 1.0 ? Conditions? */
|
||||
vertex_attribute->inline_value[0] = (float)(int16_t)(parameter & 0xFFFF);
|
||||
vertex_attribute->inline_value[1] = (float)(int16_t)(parameter >> 16);
|
||||
vertex_attribute->inline_value[2] = 0.0f;
|
||||
vertex_attribute->inline_value[3] = 1.0f;
|
||||
if (slot == 0) {
|
||||
pgraph_finish_inline_buffer_vertex(pg);
|
||||
assert(false); /* FIXME: Untested */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -2638,7 +2710,6 @@ void pgraph_handle_method(NV2AState *d,
|
|||
* 2.0f + 1) / 65535.0f;
|
||||
if ((slot == 0) && (part == 1)) {
|
||||
pgraph_finish_inline_buffer_vertex(pg);
|
||||
assert(false); /* FIXME: Untested */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -3364,7 +3435,15 @@ static void pgraph_bind_shaders(PGRAPHState *pg)
|
|||
last_y = y;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
/* FIXME: We should memset(state, 0x00, sizeof(state)) instead */
|
||||
memset(state.psh.rgb_inputs, 0, sizeof(state.psh.rgb_inputs));
|
||||
memset(state.psh.rgb_outputs, 0, sizeof(state.psh.rgb_outputs));
|
||||
memset(state.psh.alpha_inputs, 0, sizeof(state.psh.alpha_inputs));
|
||||
memset(state.psh.alpha_outputs, 0, sizeof(state.psh.alpha_outputs));
|
||||
|
||||
/* Copy content of enabled combiner stages */
|
||||
unsigned int num_stages = pg->regs[NV_PGRAPH_COMBINECTL] & 0xFF;
|
||||
for (i = 0; i < num_stages; i++) {
|
||||
state.psh.rgb_inputs[i] = pg->regs[NV_PGRAPH_COMBINECOLORI0 + i * 4];
|
||||
state.psh.rgb_outputs[i] = pg->regs[NV_PGRAPH_COMBINECOLORO0 + i * 4];
|
||||
state.psh.alpha_inputs[i] = pg->regs[NV_PGRAPH_COMBINEALPHAI0 + i * 4];
|
||||
|
@ -3439,7 +3518,7 @@ static void pgraph_bind_shaders(PGRAPHState *pg)
|
|||
pgraph_apply_anti_aliasing_factor(pg, &x_max, &y_max);
|
||||
|
||||
glUniform4i(pg->shader_binding->clip_region_loc[i],
|
||||
x_min, y_min, x_max, y_max);
|
||||
x_min, y_min, x_max + 1, y_max + 1);
|
||||
}
|
||||
|
||||
pgraph_update_shader_constants(pg, pg->shader_binding, binding_changed,
|
||||
|
@ -3787,10 +3866,10 @@ static void pgraph_update_surface(NV2AState *d, bool upload,
|
|||
glDeleteTextures(1, &pg->gl_zeta_buffer);
|
||||
pg->gl_zeta_buffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&pg->last_surface_shape, &pg->surface_shape,
|
||||
memcpy(&pg->last_surface_shape, &pg->surface_shape,
|
||||
sizeof(SurfaceShape));
|
||||
}
|
||||
|
||||
if ((color_write || (!upload && pg->surface_color.write_enabled_cache))
|
||||
&& (upload || pg->surface_color.draw_dirty)) {
|
||||
|
|
|
@ -1141,7 +1141,7 @@ void CxbxReserveNV2AMemory(NV2AState *d)
|
|||
}
|
||||
}
|
||||
|
||||
printf("[0x%.4X] INIT: Allocated %d MiB of Xbox NV2A PRAMIN memory at 0x%.8p to 0x%.8p\n",
|
||||
printf("[0x%.4X] INIT: Allocated %d MiB of Xbox NV2A PRAMIN memory at 0x%.8x to 0x%.8x\n",
|
||||
GetCurrentThreadId(), d->pramin.ramin_size / ONE_MB, (uintptr_t)d->pramin.ramin_ptr, (uintptr_t)d->pramin.ramin_ptr + d->pramin.ramin_size - 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ public:
|
|||
void Reset();
|
||||
|
||||
// State Getter: Used for HLE reading of device state
|
||||
NV2AState* GetDeviceState() { return m_nv2a_state; };
|
||||
inline NV2AState* GetDeviceState() { return m_nv2a_state; };
|
||||
|
||||
uint32_t IORead(int barIndex, uint32_t port, unsigned size);
|
||||
void IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size);
|
||||
|
|
|
@ -335,6 +335,8 @@
|
|||
#define NV_PGRAPH_FIFO 0x00000720
|
||||
# define NV_PGRAPH_FIFO_ACCESS (1 << 0)
|
||||
#define NV_PGRAPH_RDI_INDEX 0x00000750
|
||||
# define NV_PGRAPH_RDI_INDEX_ADDRESS 0x00001FFC
|
||||
# define NV_PGRAPH_RDI_INDEX_SELECT 0x01FF0000
|
||||
#define NV_PGRAPH_RDI_DATA 0x00000754
|
||||
#define NV_PGRAPH_FFINTFC_ST2 0x00000764
|
||||
#define NV_PGRAPH_CHANNEL_CTX_TABLE 0x00000780
|
||||
|
@ -691,6 +693,7 @@
|
|||
#define NV_PCRTC_CONFIG 0x00000804
|
||||
#define NV_PCRTC_RASTER 0x00000808
|
||||
|
||||
|
||||
#define NV_PVIDEO_DEBUG_2 0x00000088
|
||||
#define NV_PVIDEO_DEBUG_3 0x0000008C
|
||||
#define NV_PVIDEO_INTR 0x00000100
|
||||
|
@ -832,7 +835,7 @@
|
|||
# define NV_PRAMDAC_PLL_TEST_COUNTER_NVPLL_LOCK (1 << 29)
|
||||
# define NV_PRAMDAC_PLL_TEST_COUNTER_MPLL_LOCK (1 << 30)
|
||||
# define NV_PRAMDAC_PLL_TEST_COUNTER_VPLL_LOCK (1 << 31)
|
||||
#define NV_PRAMDAC_GENERAL_CONTROL 0x00680600
|
||||
#define NV_PRAMDAC_GENERAL_CONTROL 0x00000600
|
||||
# define NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON (3 << 4)
|
||||
# define NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_SEL (1 << 8)
|
||||
# define NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL (1 << 12)
|
||||
|
@ -840,6 +843,14 @@
|
|||
# define NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS (1 << 20)
|
||||
# define NV_PRAMDAC_GENERAL_CONTROL_PIPE_LONG (2 << 28)
|
||||
|
||||
#define NV_PRAMDAC_FP_VDISPLAY_END 0x00000800
|
||||
#define NV_PRAMDAC_FP_VCRTC 0x00000808
|
||||
#define NV_PRAMDAC_FP_VSYNC_END 0x00000810
|
||||
#define NV_PRAMDAC_FP_VVALID_END 0x00000818
|
||||
#define NV_PRAMDAC_FP_HDISPLAY_END 0x00000820
|
||||
#define NV_PRAMDAC_FP_HCRTC 0x00000828
|
||||
#define NV_PRAMDAC_FP_HVALID_END 0x00000838
|
||||
|
||||
#define NV_PRMCIO_ARX 0x006013c0
|
||||
#define NV_PRMCIO_AR__WRITE 0x006013c0
|
||||
#define NV_PRMCIO_AR__READ 0x006013c1
|
||||
|
@ -1795,6 +1806,14 @@
|
|||
#define NV_IGRAPH_XF_LTC1_L6 0x12
|
||||
#define NV_IGRAPH_XF_LTC1_L7 0x13
|
||||
|
||||
/* These RDI select values appear to be named by MS.
|
||||
* nvidia seems to refer to RDI_INDEX_VTX_CONSTANTS0 by RDI_RAMSEL_XL_XFCTX.
|
||||
* However, we don't have other nvidia names; so we use these aliases for now.
|
||||
* Eventually we'll probably adopt nouveau names for these internals.
|
||||
*/
|
||||
#define RDI_INDEX_VTX_CONSTANTS0 0x17
|
||||
#define RDI_INDEX_VTX_CONSTANTS1 0xCC
|
||||
|
||||
|
||||
#define NV2A_VERTEX_ATTR_POSITION 0
|
||||
#define NV2A_VERTEX_ATTR_WEIGHT 1
|
||||
|
|
Loading…
Reference in New Issue