Merge pull request #2157 from NZJenkins/tidy-mip-code
Tidy mip code and work around DXT crash with small textures
This commit is contained in:
commit
6db6256e45
|
@ -1542,6 +1542,14 @@ bool ConvertD3DTextureToARGBBuffer(
|
||||||
AdditionalArgument = DstRowPitch;
|
AdditionalArgument = DstRowPitch;
|
||||||
|
|
||||||
if (EmuXBFormatIsCompressed(X_Format)) {
|
if (EmuXBFormatIsCompressed(X_Format)) {
|
||||||
|
if (SrcWidth < 4 || SrcHeight < 4) {
|
||||||
|
// HACK: The compressed DXT conversion code currently writes more pixels than it should, which can cause a crash.
|
||||||
|
// This code will get hit when converting compressed texture mipmaps on hardware that somehow doesn't support DXT natively
|
||||||
|
// (or lied when Cxbx asked it if it does!)
|
||||||
|
EmuLog(LOG_LEVEL::WARNING, "Converting DXT textures smaller than a block is not currently implemented. Ignoring conversion!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// All compressed formats (DXT1, DXT3 and DXT5) encode blocks of 4 pixels on 4 lines
|
// All compressed formats (DXT1, DXT3 and DXT5) encode blocks of 4 pixels on 4 lines
|
||||||
SrcHeight = (SrcHeight + 3) / 4;
|
SrcHeight = (SrcHeight + 3) / 4;
|
||||||
DstRowPitch *= 4;
|
DstRowPitch *= 4;
|
||||||
|
@ -5697,7 +5705,6 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex
|
||||||
bool bCubemap = pPixelContainer->Format & X_D3DFORMAT_CUBEMAP;
|
bool bCubemap = pPixelContainer->Format & X_D3DFORMAT_CUBEMAP;
|
||||||
bool bSwizzled = EmuXBFormatIsSwizzled(X_Format);
|
bool bSwizzled = EmuXBFormatIsSwizzled(X_Format);
|
||||||
bool bCompressed = EmuXBFormatIsCompressed(X_Format);
|
bool bCompressed = EmuXBFormatIsCompressed(X_Format);
|
||||||
DWORD dwMinSize = (bCompressed) ? 4 : 1;
|
|
||||||
UINT dwBPP = EmuXBFormatBytesPerPixel(X_Format);
|
UINT dwBPP = EmuXBFormatBytesPerPixel(X_Format);
|
||||||
UINT dwMipMapLevels = CxbxGetPixelContainerMipMapLevels(pPixelContainer);
|
UINT dwMipMapLevels = CxbxGetPixelContainerMipMapLevels(pPixelContainer);
|
||||||
UINT dwWidth, dwHeight, dwDepth, dwRowPitch, dwSlicePitch;
|
UINT dwWidth, dwHeight, dwDepth, dwRowPitch, dwSlicePitch;
|
||||||
|
@ -5731,22 +5738,6 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex
|
||||||
LOG_TEST_CASE("CreateHostResource : Depth != 1");
|
LOG_TEST_CASE("CreateHostResource : Depth != 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following is necessary for DXT* textures (4x4 blocks minimum)
|
|
||||||
// TODO: Figure out if this is necessary under other circumstances?
|
|
||||||
if (bCompressed) {
|
|
||||||
if (dwWidth < dwMinSize) {
|
|
||||||
LOG_TEST_CASE("CreateHostResource : dwWidth < dwMinSize");
|
|
||||||
EmuLog(LOG_LEVEL::WARNING, "Expanding %s width (%d->%d)", ResourceTypeName, dwWidth, dwMinSize);
|
|
||||||
dwWidth = dwMinSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dwHeight < dwMinSize) {
|
|
||||||
LOG_TEST_CASE("CreateHostResource : dwHeight < dwMinSize");
|
|
||||||
EmuLog(LOG_LEVEL::WARNING, "Expanding %s height (%d->%d)", ResourceTypeName, dwHeight, dwMinSize);
|
|
||||||
dwHeight = dwMinSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// One of these will be created : each also has an intermediate copy to allow UpdateTexture to work
|
// One of these will be created : each also has an intermediate copy to allow UpdateTexture to work
|
||||||
// This means we don't need to lock the GPU resource anymore, so we can use D3DPOOL_DEFAULT to allow Stretch/CopyRects to work!
|
// This means we don't need to lock the GPU resource anymore, so we can use D3DPOOL_DEFAULT to allow Stretch/CopyRects to work!
|
||||||
IDirect3DSurface *pNewHostSurface = nullptr; // for X_D3DRTYPE_SURFACE
|
IDirect3DSurface *pNewHostSurface = nullptr; // for X_D3DRTYPE_SURFACE
|
||||||
|
@ -5962,23 +5953,37 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex
|
||||||
DWORD dwCubeFaceOffset = 0;
|
DWORD dwCubeFaceOffset = 0;
|
||||||
DWORD dwCubeFaceSize = 0;
|
DWORD dwCubeFaceSize = 0;
|
||||||
D3DCUBEMAP_FACES last_face = (bCubemap) ? D3DCUBEMAP_FACE_NEGATIVE_Z : D3DCUBEMAP_FACE_POSITIVE_X;
|
D3DCUBEMAP_FACES last_face = (bCubemap) ? D3DCUBEMAP_FACE_NEGATIVE_Z : D3DCUBEMAP_FACE_POSITIVE_X;
|
||||||
|
|
||||||
|
// Block size only applies to compressed DXT formats
|
||||||
|
// DXT1 block size is 8 bytes
|
||||||
|
// Other Xbox DXT formats are 16 bytes
|
||||||
|
DWORD blockSize = 0;
|
||||||
|
if (bCompressed) {
|
||||||
|
blockSize = X_Format == xbox::X_D3DFMT_DXT1 ? 8 : 16;
|
||||||
|
}
|
||||||
|
|
||||||
for (int face = D3DCUBEMAP_FACE_POSITIVE_X; face <= last_face; face++) {
|
for (int face = D3DCUBEMAP_FACE_POSITIVE_X; face <= last_face; face++) {
|
||||||
// As we iterate through mipmap levels, we'll adjust the source resource offset
|
// As we iterate through mipmap levels, we'll adjust the source resource offset
|
||||||
DWORD dwMipOffset = 0;
|
DWORD dwMipOffset = 0;
|
||||||
DWORD dwMipWidth = dwWidth;
|
DWORD pxMipWidth = dwWidth;
|
||||||
DWORD dwMipHeight = dwHeight;
|
DWORD pxMipHeight = dwHeight;
|
||||||
DWORD dwMipDepth = dwDepth;
|
DWORD pxMipDepth = dwDepth;
|
||||||
DWORD dwMipRowPitch = dwRowPitch;
|
DWORD dwMipRowPitch = dwRowPitch;
|
||||||
DWORD dwSrcSlicePitch = dwMipRowPitch * dwMipHeight; // TODO
|
DWORD dwSrcSlicePitch = dwMipRowPitch * pxMipHeight; // TODO
|
||||||
|
|
||||||
for (unsigned int mipmap_level = 0; mipmap_level < dwMipMapLevels; mipmap_level++) {
|
for (unsigned int mipmap_level = 0; mipmap_level < dwMipMapLevels; mipmap_level++) {
|
||||||
|
|
||||||
// Calculate size of this mipmap level
|
// Calculate size of this mipmap level
|
||||||
DWORD dwMipSize = dwMipRowPitch * dwMipHeight;
|
DWORD numRows = pxMipHeight;
|
||||||
|
|
||||||
if (bCompressed) {
|
if (bCompressed) {
|
||||||
dwMipSize /= 4;
|
// Each row contains a 4x4 pixel blocks, instead of single pixels
|
||||||
|
// So divide by 4 to get the number of rows
|
||||||
|
numRows = (numRows + 3) / 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DWORD dwMipSize = dwMipRowPitch * numRows;
|
||||||
|
|
||||||
// Lock the host resource
|
// Lock the host resource
|
||||||
D3DLOCKED_RECT LockedRect = {};
|
D3DLOCKED_RECT LockedRect = {};
|
||||||
D3DLOCKED_BOX LockedBox = {};
|
D3DLOCKED_BOX LockedBox = {};
|
||||||
|
@ -6039,7 +6044,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex
|
||||||
if (X_Format == xbox::X_D3DFMT_P8 && g_pXbox_Palette_Data[iTextureStage] == nullptr) {
|
if (X_Format == xbox::X_D3DFMT_P8 && g_pXbox_Palette_Data[iTextureStage] == nullptr) {
|
||||||
LOG_TEST_CASE("Palettized texture bound without a palette");
|
LOG_TEST_CASE("Palettized texture bound without a palette");
|
||||||
|
|
||||||
memset(pDst, 0, dwDstRowPitch * dwMipHeight);
|
memset(pDst, 0, dwDstRowPitch * pxMipHeight);
|
||||||
skipDueToNoPalette = true;
|
skipDueToNoPalette = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6047,7 +6052,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex
|
||||||
if (!skipDueToNoPalette) {
|
if (!skipDueToNoPalette) {
|
||||||
if (!ConvertD3DTextureToARGBBuffer(
|
if (!ConvertD3DTextureToARGBBuffer(
|
||||||
X_Format,
|
X_Format,
|
||||||
pSrc, dwMipWidth, dwMipHeight, dwMipRowPitch, dwSrcSlicePitch,
|
pSrc, pxMipWidth, pxMipHeight, dwMipRowPitch, dwSrcSlicePitch,
|
||||||
pDst, dwDstRowPitch, dwDstSlicePitch,
|
pDst, dwDstRowPitch, dwDstSlicePitch,
|
||||||
dwDepth,
|
dwDepth,
|
||||||
iTextureStage)) {
|
iTextureStage)) {
|
||||||
|
@ -6058,7 +6063,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex
|
||||||
else if (bSwizzled) {
|
else if (bSwizzled) {
|
||||||
// First we need to unswizzle the texture data
|
// First we need to unswizzle the texture data
|
||||||
EmuUnswizzleBox(
|
EmuUnswizzleBox(
|
||||||
pSrc, dwMipWidth, dwMipHeight, dwMipDepth,
|
pSrc, pxMipWidth, pxMipHeight, pxMipDepth,
|
||||||
dwBPP,
|
dwBPP,
|
||||||
pDst, dwDstRowPitch, dwDstSlicePitch
|
pDst, dwDstRowPitch, dwDstSlicePitch
|
||||||
);
|
);
|
||||||
|
@ -6082,12 +6087,12 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
*/
|
*/
|
||||||
if ((dwDstRowPitch == dwMipRowPitch) && (dwMipRowPitch == dwMipWidth * dwBPP)) {
|
if ((dwDstRowPitch == dwMipRowPitch) && (dwMipRowPitch == pxMipWidth * dwBPP)) {
|
||||||
memcpy(pDst, pSrc, dwMipSize);
|
memcpy(pDst, pSrc, dwMipSize);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (DWORD v = 0; v < dwMipHeight; v++) {
|
for (DWORD v = 0; v < pxMipHeight; v++) {
|
||||||
memcpy(pDst, pSrc, dwMipWidth * dwBPP);
|
memcpy(pDst, pSrc, pxMipWidth * dwBPP);
|
||||||
pDst += dwDstRowPitch;
|
pDst += dwDstRowPitch;
|
||||||
pSrc += dwMipRowPitch;
|
pSrc += dwMipRowPitch;
|
||||||
}
|
}
|
||||||
|
@ -6125,17 +6130,24 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex
|
||||||
|
|
||||||
// Calculate the next mipmap level dimensions
|
// Calculate the next mipmap level dimensions
|
||||||
dwMipOffset += dwMipSize;
|
dwMipOffset += dwMipSize;
|
||||||
if (dwMipWidth > dwMinSize) {
|
if (pxMipWidth > 1) {
|
||||||
dwMipWidth /= 2;
|
pxMipWidth /= 2;
|
||||||
|
|
||||||
|
// Update the row pitch
|
||||||
dwMipRowPitch /= 2;
|
dwMipRowPitch /= 2;
|
||||||
|
|
||||||
|
// The pitch can't be less than a block
|
||||||
|
if (dwMipRowPitch < blockSize) {
|
||||||
|
dwMipRowPitch = blockSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dwMipHeight > dwMinSize) {
|
if (pxMipHeight > 1) {
|
||||||
dwMipHeight /= 2;
|
pxMipHeight /= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dwMipDepth > 1) {
|
if (pxMipDepth > 1) {
|
||||||
dwMipDepth /= 2;
|
pxMipDepth /= 2;
|
||||||
}
|
}
|
||||||
} // for mipmap levels
|
} // for mipmap levels
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue