Prepare for unswizzling in 3D

This commit is contained in:
patrickvl 2018-04-07 21:08:31 +02:00
parent 569bd96c16
commit ff8fd69ca3
3 changed files with 130 additions and 89 deletions

View File

@ -821,6 +821,7 @@ VOID CxbxGetPixelContainerMeasures
DWORD dwLevel,
UINT *pWidth,
UINT *pHeight,
UINT *pDepth,
UINT *pPitch,
UINT *pSize
);
@ -831,12 +832,14 @@ size_t GetXboxResourceSize(XTL::X_D3DResource* pXboxResource)
switch (GetXboxCommonResourceType(pXboxResource)) {
case X_D3DCOMMON_TYPE_SURFACE:
case X_D3DCOMMON_TYPE_TEXTURE:
uint SrcPitch, SrcSize, Width, Height;
uint SrcPitch, SrcSize, Width, Height, Depth;
// TODO : Accumulate all mipmap levels!!!
CxbxGetPixelContainerMeasures(
(XTL::X_D3DPixelContainer*)pXboxResource,
0, // dwLevel
&Width,
&Height,
&Depth,
&SrcPitch,
&SrcSize
);
@ -1096,9 +1099,10 @@ VOID XTL::CxbxSetPixelContainerHeader
VOID CxbxGetPixelContainerMeasures
(
XTL::X_D3DPixelContainer *pPixelContainer,
DWORD dwLevel,
DWORD dwLevel, // unused
UINT *pWidth,
UINT *pHeight,
UINT *pDepth,
UINT *pPitch,
UINT *pSize
)
@ -1108,6 +1112,7 @@ VOID CxbxGetPixelContainerMeasures
if (Size != 0)
{
*pDepth = 1;
*pWidth = ((Size & X_D3DSIZE_WIDTH_MASK) /* >> X_D3DSIZE_WIDTH_SHIFT*/) + 1;
*pHeight = ((Size & X_D3DSIZE_HEIGHT_MASK) >> X_D3DSIZE_HEIGHT_SHIFT) + 1;
*pPitch = (((Size & X_D3DSIZE_PITCH_MASK) >> X_D3DSIZE_PITCH_SHIFT) + 1) * X_D3DTEXTURE_PITCH_ALIGNMENT;
@ -1116,8 +1121,10 @@ VOID CxbxGetPixelContainerMeasures
{
DWORD l2w = (pPixelContainer->Format & X_D3DFORMAT_USIZE_MASK) >> X_D3DFORMAT_USIZE_SHIFT;
DWORD l2h = (pPixelContainer->Format & X_D3DFORMAT_VSIZE_MASK) >> X_D3DFORMAT_VSIZE_SHIFT;
DWORD l2d = (pPixelContainer->Format & X_D3DFORMAT_PSIZE_MASK) >> X_D3DFORMAT_PSIZE_SHIFT;
DWORD dwBPP = EmuXBFormatBitsPerPixel(X_Format);
*pDepth = 1 << l2d;
*pHeight = 1 << l2h;
*pWidth = 1 << l2w;
*pPitch = *pWidth * dwBPP / 8;
@ -1134,22 +1141,27 @@ bool ConvertD3DTextureToARGBBuffer(
XTL::X_D3DFORMAT X_Format,
uint8 *pSrc,
int SrcWidth, int SrcHeight,
uint SrcPitch,
uint SrcRowPitch,
uint8 *pDest, int DestPitch,
int TextureStage = 0
uint uiDepth = 1,
int iTextureStage = 0
)
{
const XTL::FormatToARGBRow ConvertRowToARGB = EmuXBFormatComponentConverter(X_Format);
if (ConvertRowToARGB == nullptr)
return false; // Unhandled conversion
uint SrcSlicePitch = SrcRowPitch * SrcHeight;
SrcSlicePitch = ROUND_UP(SrcSlicePitch, X_D3DTEXTURE_PITCH_ALIGNMENT); // TODO : Is this correct?
uint8 *unswizleBuffer = nullptr;
if (XTL::EmuXBFormatIsSwizzled(X_Format)) {
unswizleBuffer = (uint8*)malloc(SrcPitch * SrcHeight); // TODO : Reuse buffer when performance is important
unswizleBuffer = (uint8*)malloc(SrcSlicePitch * uiDepth); // TODO : Reuse buffer when performance is important
// First we need to unswizzle the texture data
XTL::EmuUnswizzleRect(
pSrc, SrcWidth, SrcHeight, 1, unswizleBuffer,
SrcPitch, {}, {}, EmuXBFormatBytesPerPixel(X_Format)
XTL::EmuUnswizzleBox(
pSrc, SrcWidth, SrcRowPitch, SrcHeight, SrcSlicePitch, uiDepth,
unswizleBuffer,
EmuXBFormatBytesPerPixel(X_Format)
);
// Convert colors from the unswizzled buffer
pSrc = unswizleBuffer;
@ -1157,11 +1169,10 @@ bool ConvertD3DTextureToARGBBuffer(
int AdditionalArgument;
if (X_Format == XTL::X_D3DFMT_P8)
AdditionalArgument = (int)g_pCurrentPalette[TextureStage];
AdditionalArgument = (int)g_pCurrentPalette[iTextureStage];
else
AdditionalArgument = DestPitch;
DWORD SrcRowOff = 0;
uint8 *pDestRow = pDest;
if (EmuXBFormatIsCompressed(X_Format)) {
// All compressed formats (DXT1, DXT3 and DXT5) encode blocks of 4 pixels on 4 lines
@ -1169,11 +1180,17 @@ bool ConvertD3DTextureToARGBBuffer(
DestPitch *= 4;
}
for (int y = 0; y < SrcHeight; y++) {
*(int*)pDestRow = AdditionalArgument; // Dirty hack, to avoid an extra parameter to all conversion callbacks
ConvertRowToARGB(pSrc + SrcRowOff, pDestRow, SrcWidth);
SrcRowOff += SrcPitch;
pDestRow += DestPitch;
DWORD SrcSliceOff = 0;
for (int z = 0; z < uiDepth; z++) {
DWORD SrcRowOff = SrcSliceOff;
for (int y = 0; y < SrcHeight; y++) {
*(int*)pDestRow = AdditionalArgument; // Dirty hack, to avoid an extra parameter to all conversion callbacks
ConvertRowToARGB(pSrc + SrcRowOff, pDestRow, SrcWidth);
SrcRowOff += SrcRowPitch;
pDestRow += DestPitch;
}
SrcSliceOff += SrcSlicePitch;
}
if (unswizleBuffer)
@ -1196,12 +1213,13 @@ uint8 *XTL::ConvertD3DTextureToARGB(
if (ConvertRowToARGB == nullptr)
return nullptr; // Unhandled conversion
uint SrcPitch, SrcSize;
uint SrcPitch, SrcSize, SrcDepth;
CxbxGetPixelContainerMeasures(
pXboxPixelContainer,
0, // dwLevel
(UINT*)pWidth,
(UINT*)pHeight,
&SrcDepth,
&SrcPitch,
&SrcSize
);
@ -1215,6 +1233,7 @@ uint8 *XTL::ConvertD3DTextureToARGB(
X_Format,
pSrc, *pWidth, *pHeight, SrcPitch,
pDest, DestPitch,
1, // Depth
TextureStage);
// NOTE : Caller must take ownership!
@ -4058,9 +4077,7 @@ DWORD WINAPI XTL::EMUPATCH(D3DDevice_Swap)
return result;
}
// ******************************************************************
// * patch: IDirect3DResource8_Register
// ******************************************************************
// Was patch: IDirect3DResource8_Register
void CreateHostResource(XTL::X_D3DResource *pThis, int TextureStage, DWORD dwSize)
{
using namespace XTL;
@ -4219,14 +4236,14 @@ void CreateHostResource(XTL::X_D3DResource *pThis, int TextureStage, DWORD dwSiz
}
}
UINT dwWidth, dwHeight, dwBPP, dwDepth = 1, dwPitch, dwMipMapLevels, uiSize;
UINT dwWidth, dwHeight, dwBPP, dwDepth, dwPitch, dwMipMapLevels, uiSize;
bool bSwizzled = EmuXBFormatIsSwizzled(X_Format);
bool bCompressed = EmuXBFormatIsCompressed(X_Format);
bool bCubemap = pPixelContainer->Format & X_D3DFORMAT_CUBEMAP;
dwBPP = EmuXBFormatBytesPerPixel(X_Format);
// Interpret Width/Height/BPP
CxbxGetPixelContainerMeasures(pPixelContainer, 0, &dwWidth, &dwHeight, &dwPitch, &uiSize);
CxbxGetPixelContainerMeasures(pPixelContainer, 0, &dwWidth, &dwHeight, &dwDepth, &dwPitch, &uiSize);
if (pPixelContainer->Size == 0) {
dwMipMapLevels = (pPixelContainer->Format & X_D3DFORMAT_MIPMAP_MASK) >> X_D3DFORMAT_MIPMAP_SHIFT;
}
@ -4234,6 +4251,11 @@ void CreateHostResource(XTL::X_D3DResource *pThis, int TextureStage, DWORD dwSiz
dwMipMapLevels = 1;
}
if (dwDepth != 1) {
EmuWarning("Unsupported depth (%d) - resetting to 1 for now", dwDepth);
dwDepth = 1;
}
if(bSwizzled || bCompressed)
{
uint32 w = dwWidth;
@ -4457,14 +4479,11 @@ void CreateHostResource(XTL::X_D3DResource *pThis, int TextureStage, DWORD dwSiz
{
if (bSwizzled)
{
RECT iRect = { 0,0,0,0 };
POINT iPoint = { 0,0 };
const DWORD dwSlicePitch = 0; // only needed for volume textures (dwDepth > 1)
// First we need to unswizzle the texture data
XTL::EmuUnswizzleRect
(
pSrc + dwMipOffs, dwMipWidth, dwMipHeight, dwDepth, LockedRect.pBits,
LockedRect.Pitch, iRect, iPoint, dwBPP
XTL::EmuUnswizzleBox(
pSrc + dwMipOffs, dwMipWidth, LockedRect.Pitch, dwMipHeight, dwSlicePitch, dwDepth,
LockedRect.pBits, dwBPP
);
}
else if (bCompressed)

View File

@ -931,7 +931,7 @@ static const FormatInfo FormatInfos[] = {
/* 0x33 X_D3DFMT_V16U16 */ { 32, Swzzld, NoCmpnts, XTL::D3DFMT_V16U16 },
/* 0x34 undefined */ {},
/* 0x35 X_D3DFMT_LIN_L16 */ { 16, Linear, _____L16, XTL::D3DFMT_A8L8 , Texture, "X_D3DFMT_LIN_L16 -> D3DFMT_A8L8" },
/* 0x36 X_D3DFMT_LIN_V16U16 */ { 32, Linear, NoCmpnts, XTL::D3DFMT_V16U16 },
/* 0x36 X_D3DFMT_LIN_V16U16 */ { 32, Linear, NoCmpnts, XTL::D3DFMT_V16U16 }, // Note : Seems ununsed on Xbox
/* 0x37 X_D3DFMT_LIN_L6V5U5 */ { 16, Linear, __R6G5B5, XTL::D3DFMT_L6V5U5 }, // Alias : X_D3DFMT_LIN_R6G5B5
/* 0x38 X_D3DFMT_R5G5B5A1 */ { 16, Swzzld, R5G5B5A1, XTL::D3DFMT_A1R5G5B5 , Texture, "X_D3DFMT_R5G5B5A1 -> D3DFMT_A1R5G5B5" },
/* 0x39 X_D3DFMT_R4G4B4A4 */ { 16, Swzzld, R4G4B4A4, XTL::D3DFMT_A4R4G4B4 , Texture, "X_D3DFMT_R4G4B4A4 -> D3DFMT_A4R4G4B4" },
@ -1336,20 +1336,18 @@ CONST DWORD XTL::EmuD3DRenderStateSimpleEncoded[174] =
X_D3DRSSE_UNK, X_D3DRSSE_UNK, // 172
};
void XTL::EmuUnswizzleRect
void XTL::EmuUnswizzleBox
(
PVOID pSrcBuff,
DWORD dwWidth,
DWORD dwRowPitch,
DWORD dwHeight,
DWORD dwSlicePitch,
DWORD dwDepth,
PVOID pDstBuff,
DWORD dwPitch,
RECT rSrc, // Unused
POINT poDst, // Unused
DWORD dwBPP // expressed in Bytes Per Pixel
) // Source : Dxbx
{
// TODO : The following could be done using a lookup table :
DWORD dwMaskX = 0, dwMaskY = 0, dwMaskZ = 0;
for (uint i=1, j=1; (i <= dwWidth) || (i <= dwHeight) || (i <= dwDepth); i <<= 1) {
if (i < dwWidth) {
@ -1368,64 +1366,89 @@ void XTL::EmuUnswizzleRect
}
}
// get the biggest mask
DWORD dwMaskMax;
if (dwMaskX > dwMaskY)
dwMaskMax = dwMaskX;
else
dwMaskMax = dwMaskY;
DWORD dwRowPitchCorrection = dwWidth - (dwRowPitch / dwBPP);
DWORD dwSlicePitchCorrection = ((dwHeight * dwRowPitch) - dwSlicePitch) / dwBPP;
if (dwMaskZ > dwMaskMax)
dwMaskMax = dwMaskZ;
DWORD dwStartX = 0, dwOffsetX = 0;
DWORD dwStartY = 0, dwOffsetY = 0;
DWORD dwStartZ = 0, dwOffsetW = 0;
/* TODO : Use values from poDst and rSrc to initialize above values, after which the following makes more sense:
for (uint i=1; i <= dwMaskMax; i <<= 1) {
if (i <= dwMaskX) {
if (dwMaskX & i)
dwStartX |= (dwOffsetX & i);
else
dwOffsetX <<= 1;
}
if (i <= dwMaskY) {
if (dwMaskY & i)
dwStartY |= dwOffsetY & i;
else
dwOffsetY <<= 1;
}
if (i <= dwMaskZ) {
if (dwMaskZ & i)
dwStartZ |= dwOffsetZ & i;
else
dwOffsetZ <<= 1;
}
}*/
const DWORD dwStartX = 0;
const DWORD dwStartY = 0;
const DWORD dwStartZ = 0;
DWORD dwZ = dwStartZ;
for (uint z = 0; z < dwDepth; z++) {
DWORD dwY = dwStartY;
for (uint y = 0; y < dwHeight; y++) {
DWORD dwX = dwStartX;
DWORD dwYZ = dwY | dwZ;
for (uint x = 0; x < dwWidth; x++) {
uint delta = (dwX | dwYZ) * dwBPP;
memcpy(pDstBuff, (PBYTE)pSrcBuff + delta, dwBPP); // copy one pixel
pDstBuff = (PBYTE)pDstBuff + dwBPP; // Step to next pixel in destination
dwX = (dwX - dwMaskX) & dwMaskX; // step to next pixel in source
switch (dwBPP) {
case 1: {
uint8_t *pSrc = (uint8_t *)pSrcBuff;
uint8_t *pDest = (uint8_t *)pDstBuff;
for (uint z = 0; z < dwDepth; z++) {
DWORD dwY = dwStartY;
for (uint y = 0; y < dwHeight; y++) {
DWORD dwYZ = dwY | dwZ;
DWORD dwX = dwStartX;
for (uint x = 0; x < dwWidth; x++) {
uint delta = dwX | dwYZ;
*(pDest++) = pSrc[delta]; // copy one pixel
dwX = (dwX - dwMaskX) & dwMaskX; // step to next pixel in source
}
pDest += dwRowPitchCorrection; // step to next line in destination
dwY = (dwY - dwMaskY) & dwMaskY; // step to next line in source
}
pDstBuff = (PBYTE)pDstBuff + dwPitch - (dwWidth * dwBPP); // step to next line in destination
dwY = (dwY - dwMaskY) & dwMaskY; // step to next line in source
pDest += dwSlicePitchCorrection; // step to next level in destination
dwZ = (dwZ - dwMaskZ) & dwMaskZ; // step to next level in source
}
// TODO : How to step to next level in destination? Should X and Y be recalculated per level?
dwZ = (dwZ - dwMaskZ) & dwMaskZ; // step to next level in source
break;
}
} // EmuUnswizzleRect NOPATCH
case 2: {
uint16_t *pSrc = (uint16_t *)pSrcBuff;
uint16_t *pDest = (uint16_t *)pDstBuff;
for (uint z = 0; z < dwDepth; z++) {
DWORD dwY = dwStartY;
for (uint y = 0; y < dwHeight; y++) {
DWORD dwYZ = dwY | dwZ;
DWORD dwX = dwStartX;
for (uint x = 0; x < dwWidth; x++) {
uint delta = dwX | dwYZ;
*(pDest++) = pSrc[delta]; // copy one pixel
dwX = (dwX - dwMaskX) & dwMaskX; // step to next pixel in source
}
pDest += dwRowPitchCorrection; // step to next line in destination
dwY = (dwY - dwMaskY) & dwMaskY; // step to next line in source
}
pDest += dwSlicePitchCorrection; // step to next level in destination
dwZ = (dwZ - dwMaskZ) & dwMaskZ; // step to next level in source
}
break;
}
case 4: {
uint32_t *pSrc = (uint32_t *)pSrcBuff;
uint32_t *pDest = (uint32_t *)pDstBuff;
for (uint z = 0; z < dwDepth; z++) {
DWORD dwY = dwStartY;
for (uint y = 0; y < dwHeight; y++) {
DWORD dwYZ = dwY | dwZ;
DWORD dwX = dwStartX;
for (uint x = 0; x < dwWidth; x++) {
uint delta = dwX | dwYZ;
*(pDest++) = pSrc[delta]; // copy one pixel
dwX = (dwX - dwMaskX) & dwMaskX; // step to next pixel in source
}
pDest += dwRowPitchCorrection; // step to next line in destination
dwY = (dwY - dwMaskY) & dwMaskY; // step to next line in source
}
pDest += dwSlicePitchCorrection; // step to next level in destination
dwZ = (dwZ - dwMaskZ) & dwMaskZ; // step to next level in source
}
break;
}
}
} // EmuUnswizzleBox NOPATCH
namespace XTL
{

View File

@ -239,16 +239,15 @@ inline D3DPRIMITIVETYPE EmuXB2PC_D3DPrimitiveType(X_D3DPRIMITIVETYPE PrimitiveTy
return EmuPrimitiveTypeLookup[PrimitiveType];
}
extern void EmuUnswizzleRect
extern void EmuUnswizzleBox
(
PVOID pSrcBuff,
DWORD dwWidth,
DWORD dwRowPitch,
DWORD dwHeight,
DWORD dwSlicePitch,
DWORD dwDepth,
PVOID pDstBuff,
DWORD dwPitch,
RECT rSrc, // Unused
POINT poDst, // Unused
DWORD dwBPP // expressed in Bytes Per Pixel
); // NOPATCH