mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-12 17:58:37 +12:00
d3d12: Clean up texture upload code
Should be easier to read code (and spot bugs). Fix crash with mipmap and DXTCn texture format.
This commit is contained in:
parent
eda3c9084e
commit
dbcddcf5e2
1 changed files with 220 additions and 80 deletions
|
@ -144,6 +144,190 @@ struct MipmapLevelInfo
|
||||||
size_t rowPitch;
|
size_t rowPitch;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MAX2(a, b) ((a) > (b)) ? (a) : (b)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write data, assume src pixels are packed but not mipmaplevel
|
||||||
|
*/
|
||||||
|
static std::vector<MipmapLevelInfo>
|
||||||
|
writeTexelsGeneric(const char *src, char *dst, size_t widthInBlock, size_t heightInBlock, size_t blockSize, size_t mipmapCount)
|
||||||
|
{
|
||||||
|
std::vector<MipmapLevelInfo> Result;
|
||||||
|
size_t offsetInDst = 0, offsetInSrc = 0;
|
||||||
|
size_t currentHeight = heightInBlock, currentWidth = widthInBlock;
|
||||||
|
for (unsigned mipLevel = 0; mipLevel < mipmapCount; mipLevel++)
|
||||||
|
{
|
||||||
|
size_t rowPitch = powerOf2Align(currentWidth * blockSize, 256);
|
||||||
|
|
||||||
|
MipmapLevelInfo currentMipmapLevelInfo = {};
|
||||||
|
currentMipmapLevelInfo.offset = offsetInDst;
|
||||||
|
currentMipmapLevelInfo.height = currentHeight;
|
||||||
|
currentMipmapLevelInfo.width = currentWidth;
|
||||||
|
currentMipmapLevelInfo.rowPitch = rowPitch;
|
||||||
|
Result.push_back(currentMipmapLevelInfo);
|
||||||
|
|
||||||
|
for (unsigned row = 0; row < currentHeight; row++)
|
||||||
|
memcpy((char*)dst + offsetInDst + row * rowPitch, (char*)src + offsetInSrc + row * widthInBlock * blockSize, currentWidth * blockSize);
|
||||||
|
|
||||||
|
offsetInDst += currentHeight * rowPitch;
|
||||||
|
offsetInSrc += currentHeight * widthInBlock * blockSize;
|
||||||
|
currentHeight = MAX2(currentHeight / 2, 1);
|
||||||
|
currentWidth = MAX2(currentWidth / 2, 1);
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write data, assume src pixels are swizzled and but not mipmaplevel
|
||||||
|
*/
|
||||||
|
static std::vector<MipmapLevelInfo>
|
||||||
|
writeTexelsSwizzled(const char *src, char *dst, size_t widthInBlock, size_t heightInBlock, size_t blockSize, size_t mipmapCount)
|
||||||
|
{
|
||||||
|
std::vector<MipmapLevelInfo> Result;
|
||||||
|
size_t offsetInDst = 0, offsetInSrc = 0;
|
||||||
|
size_t currentHeight = heightInBlock, currentWidth = widthInBlock;
|
||||||
|
for (unsigned mipLevel = 0; mipLevel < mipmapCount; mipLevel++)
|
||||||
|
{
|
||||||
|
size_t rowPitch = powerOf2Align(currentWidth * blockSize, 256);
|
||||||
|
|
||||||
|
MipmapLevelInfo currentMipmapLevelInfo = {};
|
||||||
|
currentMipmapLevelInfo.offset = offsetInDst;
|
||||||
|
currentMipmapLevelInfo.height = currentHeight;
|
||||||
|
currentMipmapLevelInfo.width = currentWidth;
|
||||||
|
currentMipmapLevelInfo.rowPitch = rowPitch;
|
||||||
|
Result.push_back(currentMipmapLevelInfo);
|
||||||
|
|
||||||
|
u32 *castedSrc, *castedDst;
|
||||||
|
u32 log2width, log2height;
|
||||||
|
|
||||||
|
castedSrc = (u32*)src + offsetInSrc;
|
||||||
|
castedDst = (u32*)dst + offsetInDst;
|
||||||
|
|
||||||
|
log2width = (u32)(logf((float)currentWidth) / logf(2.f));
|
||||||
|
log2height = (u32)(logf((float)currentHeight) / logf(2.f));
|
||||||
|
|
||||||
|
#pragma omp parallel for
|
||||||
|
for (unsigned row = 0; row < currentHeight; row++)
|
||||||
|
for (int j = 0; j < currentWidth; j++)
|
||||||
|
castedDst[(row * rowPitch / 4) + j] = castedSrc[LinearToSwizzleAddress(j, row, 0, log2width, log2height, 0)];
|
||||||
|
|
||||||
|
offsetInDst += currentHeight * rowPitch;
|
||||||
|
offsetInSrc += currentHeight * widthInBlock * blockSize;
|
||||||
|
currentHeight = MAX2(currentHeight / 2, 1);
|
||||||
|
currentWidth = MAX2(currentWidth / 2, 1);
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write data, assume compressed (DXTCn) format
|
||||||
|
*/
|
||||||
|
static std::vector<MipmapLevelInfo>
|
||||||
|
writeCompressedTexel(const char *src, char *dst, size_t widthInBlock, size_t blockWidth, size_t heightInBlock, size_t blockHeight, size_t blockSize, size_t mipmapCount)
|
||||||
|
{
|
||||||
|
std::vector<MipmapLevelInfo> Result;
|
||||||
|
size_t offsetInDst = 0, offsetInSrc = 0;
|
||||||
|
size_t currentHeight = heightInBlock, currentWidth = widthInBlock;
|
||||||
|
for (unsigned mipLevel = 0; mipLevel < mipmapCount; mipLevel++)
|
||||||
|
{
|
||||||
|
size_t rowPitch = powerOf2Align(currentWidth * blockSize, 256);
|
||||||
|
|
||||||
|
MipmapLevelInfo currentMipmapLevelInfo = {};
|
||||||
|
currentMipmapLevelInfo.offset = offsetInDst;
|
||||||
|
currentMipmapLevelInfo.height = currentHeight * blockHeight;
|
||||||
|
currentMipmapLevelInfo.width = currentWidth * blockWidth;
|
||||||
|
currentMipmapLevelInfo.rowPitch = rowPitch;
|
||||||
|
Result.push_back(currentMipmapLevelInfo);
|
||||||
|
|
||||||
|
for (unsigned row = 0; row < currentHeight; row++)
|
||||||
|
memcpy((char*)dst + offsetInDst + row * rowPitch, (char*)src + offsetInSrc + row * currentWidth * blockSize, currentWidth * blockSize);
|
||||||
|
|
||||||
|
offsetInDst += currentHeight * rowPitch;
|
||||||
|
offsetInDst = powerOf2Align(offsetInDst, 512);
|
||||||
|
offsetInSrc += currentHeight * currentWidth * blockSize;
|
||||||
|
currentHeight = MAX2(currentHeight / 2, 1);
|
||||||
|
currentWidth = MAX2(currentWidth / 2, 1);
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write 16 bytes pixel textures, assume src pixels are packed but not mipmaplevel
|
||||||
|
*/
|
||||||
|
static std::vector<MipmapLevelInfo>
|
||||||
|
write16bTexelsGeneric(const char *src, char *dst, size_t widthInBlock, size_t heightInBlock, size_t blockSize, size_t mipmapCount)
|
||||||
|
{
|
||||||
|
std::vector<MipmapLevelInfo> Result;
|
||||||
|
size_t offsetInDst = 0, offsetInSrc = 0;
|
||||||
|
size_t currentHeight = heightInBlock, currentWidth = widthInBlock;
|
||||||
|
size_t srcPitch = widthInBlock * blockSize;
|
||||||
|
for (unsigned mipLevel = 0; mipLevel < mipmapCount; mipLevel++)
|
||||||
|
{
|
||||||
|
size_t rowPitch = powerOf2Align(currentWidth * blockSize, 256);
|
||||||
|
|
||||||
|
MipmapLevelInfo currentMipmapLevelInfo = {};
|
||||||
|
currentMipmapLevelInfo.offset = offsetInDst;
|
||||||
|
currentMipmapLevelInfo.height = currentHeight;
|
||||||
|
currentMipmapLevelInfo.width = currentWidth;
|
||||||
|
currentMipmapLevelInfo.rowPitch = rowPitch;
|
||||||
|
Result.push_back(currentMipmapLevelInfo);
|
||||||
|
|
||||||
|
unsigned short *castedDst = (unsigned short *)dst, *castedSrc = (unsigned short *)src;
|
||||||
|
|
||||||
|
for (unsigned row = 0; row < heightInBlock; row++)
|
||||||
|
for (int j = 0; j < currentWidth; j++)
|
||||||
|
{
|
||||||
|
u16 tmp = castedSrc[offsetInSrc / 2 + row * srcPitch / 2 + j];
|
||||||
|
castedDst[offsetInDst / 2 + row * rowPitch / 2 + j] = (tmp >> 8) | (tmp << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
offsetInDst += currentHeight * rowPitch;
|
||||||
|
offsetInSrc += currentHeight * widthInBlock * blockSize;
|
||||||
|
currentHeight = MAX2(currentHeight / 2, 1);
|
||||||
|
currentWidth = MAX2(currentWidth / 2, 1);
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write 16 bytes pixel textures, assume src pixels are packed but not mipmaplevel
|
||||||
|
*/
|
||||||
|
static std::vector<MipmapLevelInfo>
|
||||||
|
write16bX4TexelsGeneric(const char *src, char *dst, size_t widthInBlock, size_t heightInBlock, size_t blockSize, size_t mipmapCount)
|
||||||
|
{
|
||||||
|
std::vector<MipmapLevelInfo> Result;
|
||||||
|
size_t offsetInDst = 0, offsetInSrc = 0;
|
||||||
|
size_t currentHeight = heightInBlock, currentWidth = widthInBlock;
|
||||||
|
size_t srcPitch = widthInBlock * blockSize;
|
||||||
|
for (unsigned mipLevel = 0; mipLevel < mipmapCount; mipLevel++)
|
||||||
|
{
|
||||||
|
size_t rowPitch = powerOf2Align(currentWidth * blockSize, 256);
|
||||||
|
|
||||||
|
MipmapLevelInfo currentMipmapLevelInfo = {};
|
||||||
|
currentMipmapLevelInfo.offset = offsetInDst;
|
||||||
|
currentMipmapLevelInfo.height = currentHeight;
|
||||||
|
currentMipmapLevelInfo.width = currentWidth;
|
||||||
|
currentMipmapLevelInfo.rowPitch = rowPitch;
|
||||||
|
Result.push_back(currentMipmapLevelInfo);
|
||||||
|
|
||||||
|
unsigned short *castedDst = (unsigned short *)dst, *castedSrc = (unsigned short *)src;
|
||||||
|
|
||||||
|
for (unsigned row = 0; row < heightInBlock; row++)
|
||||||
|
for (int j = 0; j < currentWidth * 4; j++)
|
||||||
|
{
|
||||||
|
u16 tmp = castedSrc[offsetInSrc / 2 + row * srcPitch / 2 + j];
|
||||||
|
castedDst[offsetInDst / 2 + row * rowPitch / 2 + j] = (tmp >> 8) | (tmp << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
offsetInDst += currentHeight * rowPitch;
|
||||||
|
offsetInSrc += currentHeight * widthInBlock * blockSize;
|
||||||
|
currentHeight = MAX2(currentHeight / 2, 1);
|
||||||
|
currentWidth = MAX2(currentWidth / 2, 1);
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a texture residing in default heap and generate uploads commands in commandList,
|
* Create a texture residing in default heap and generate uploads commands in commandList,
|
||||||
* using a temporary texture buffer.
|
* using a temporary texture buffer.
|
||||||
|
@ -310,7 +494,7 @@ ID3D12Resource *uploadSingleTexture(
|
||||||
size_t rowPitch = powerOf2Align(blockSizeInByte * widthInBlocks, 256);
|
size_t rowPitch = powerOf2Align(blockSizeInByte * widthInBlocks, 256);
|
||||||
|
|
||||||
ID3D12Resource *Texture;
|
ID3D12Resource *Texture;
|
||||||
size_t textureSize = rowPitch * heightInBlocks * 4; // * 3 for mipmap levels
|
size_t textureSize = rowPitch * heightInBlocks * 4; // * 4 for mipmap levels
|
||||||
assert(textureBuffersHeap.canAlloc(textureSize));
|
assert(textureBuffersHeap.canAlloc(textureSize));
|
||||||
size_t heapOffset = textureBuffersHeap.alloc(textureSize);
|
size_t heapOffset = textureBuffersHeap.alloc(textureSize);
|
||||||
|
|
||||||
|
@ -327,85 +511,41 @@ ID3D12Resource *uploadSingleTexture(
|
||||||
auto pixels = vm::get_ptr<const u8>(texaddr);
|
auto pixels = vm::get_ptr<const u8>(texaddr);
|
||||||
void *textureData;
|
void *textureData;
|
||||||
check(Texture->Map(0, nullptr, (void**)&textureData));
|
check(Texture->Map(0, nullptr, (void**)&textureData));
|
||||||
|
std::vector<MipmapLevelInfo> mipInfos;
|
||||||
|
|
||||||
// Upload with correct rowpitch
|
switch (format)
|
||||||
std::vector<MipmapLevelInfo> mipinfos;
|
|
||||||
size_t offsetInDst = 0, offsetInSrc = 0;
|
|
||||||
size_t currentHeight = heightInBlocks, currentWidth = widthInBlocks;
|
|
||||||
|
|
||||||
unsigned tmp = texture.GetMipmap();
|
|
||||||
for (unsigned mipLevel = 0; mipLevel < texture.GetMipmap(); mipLevel++)
|
|
||||||
{
|
{
|
||||||
MipmapLevelInfo currentMipmapLevelInfo = {};
|
case CELL_GCM_TEXTURE_A8R8G8B8:
|
||||||
currentMipmapLevelInfo.offset = offsetInDst;
|
{
|
||||||
currentMipmapLevelInfo.height = currentHeight;
|
if (is_swizzled)
|
||||||
currentMipmapLevelInfo.width = currentWidth;
|
mipInfos = writeTexelsSwizzled((char*)pixels, (char*)textureData, w, h, 4, texture.GetMipmap());
|
||||||
|
else
|
||||||
for (unsigned row = 0; row < currentHeight; row++)
|
mipInfos = writeTexelsGeneric((char*)pixels, (char*)textureData, w, h, 4, texture.GetMipmap());
|
||||||
{
|
break;
|
||||||
switch (format)
|
}
|
||||||
{
|
case CELL_GCM_TEXTURE_A4R4G4B4:
|
||||||
case CELL_GCM_TEXTURE_A8R8G8B8:
|
case CELL_GCM_TEXTURE_R5G6B5:
|
||||||
{
|
{
|
||||||
currentMipmapLevelInfo.rowPitch = powerOf2Align(currentWidth * blockSizeInByte, 256);
|
mipInfos = write16bTexelsGeneric((char*)pixels, (char*)textureData, w, h, 2, texture.GetMipmap());
|
||||||
if (is_swizzled)
|
break;
|
||||||
{
|
}
|
||||||
u32 *src, *dst;
|
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT:
|
||||||
u32 log2width, log2height;
|
{
|
||||||
|
mipInfos = write16bX4TexelsGeneric((char*)pixels, (char*)textureData, w, h, 8, texture.GetMipmap());
|
||||||
src = (u32*)pixels + offsetInSrc;
|
break;
|
||||||
dst = (u32*)textureData + offsetInDst;
|
}
|
||||||
|
case CELL_GCM_TEXTURE_COMPRESSED_DXT1:
|
||||||
log2width = (u32)(logf((float)currentWidth) / logf(2.f));
|
case CELL_GCM_TEXTURE_COMPRESSED_DXT23:
|
||||||
log2height = (u32)(logf((float)currentHeight) / logf(2.f));
|
case CELL_GCM_TEXTURE_COMPRESSED_DXT45:
|
||||||
|
{
|
||||||
#pragma omp parallel for
|
mipInfos = writeCompressedTexel((char*)pixels, (char*)textureData, widthInBlocks, blockWidthInPixel, heightInBlocks, blockHeightInPixel, blockSizeInByte, texture.GetMipmap());
|
||||||
for (int j = 0; j < w; j++)
|
break;
|
||||||
dst[(row * currentMipmapLevelInfo.rowPitch / 4) + j] = src[LinearToSwizzleAddress(j, row, 0, log2width, log2height, 0)];
|
}
|
||||||
}
|
default:
|
||||||
else
|
{
|
||||||
memcpy((char*)textureData + offsetInDst + row * currentMipmapLevelInfo.rowPitch, (char*)pixels + offsetInSrc + row * widthInBlocks * blockSizeInByte, currentWidth * blockSizeInByte);
|
mipInfos = writeTexelsGeneric((char*)pixels, (char*)textureData, w, h, blockSizeInByte, texture.GetMipmap());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CELL_GCM_TEXTURE_A4R4G4B4:
|
|
||||||
case CELL_GCM_TEXTURE_R5G6B5:
|
|
||||||
{
|
|
||||||
currentMipmapLevelInfo.rowPitch = rowPitch;
|
|
||||||
unsigned short *dst = (unsigned short *)textureData, *src = (unsigned short *)pixels;
|
|
||||||
|
|
||||||
for (int j = 0; j < w; j++)
|
|
||||||
{
|
|
||||||
u16 tmp = src[offsetInSrc / 2 + row * srcPitch / 2 + j];
|
|
||||||
dst[offsetInDst / 2 + row * rowPitch / 2 + j] = (tmp >> 8) | (tmp << 8);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT:
|
|
||||||
{
|
|
||||||
currentMipmapLevelInfo.rowPitch = rowPitch;
|
|
||||||
unsigned short *dst = (unsigned short *)textureData, *src = (unsigned short *)pixels;
|
|
||||||
|
|
||||||
for (int j = 0; j < w * 4; j++)
|
|
||||||
{
|
|
||||||
unsigned short tmp = src[offsetInSrc / 2 + row * w * 4 + j];
|
|
||||||
dst[offsetInDst / 2 + row * w * 4 + j] = (tmp >> 8) | (tmp << 8);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
currentMipmapLevelInfo.rowPitch = rowPitch;
|
|
||||||
streamBuffer((char*)textureData + offsetInDst + row * rowPitch, (char*)pixels + offsetInSrc + row * srcPitch, srcPitch);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
offsetInDst += currentHeight * currentMipmapLevelInfo.rowPitch;
|
|
||||||
offsetInDst = powerOf2Align(offsetInDst, 256);
|
|
||||||
offsetInSrc += currentHeight * widthInBlocks * blockSizeInByte;
|
|
||||||
mipinfos.push_back(currentMipmapLevelInfo);
|
|
||||||
currentHeight /= 2;
|
|
||||||
currentWidth /= 2;
|
|
||||||
}
|
}
|
||||||
Texture->Unmap(0, nullptr);
|
Texture->Unmap(0, nullptr);
|
||||||
|
|
||||||
|
@ -427,11 +567,11 @@ ID3D12Resource *uploadSingleTexture(
|
||||||
|
|
||||||
|
|
||||||
size_t miplevel = 0;
|
size_t miplevel = 0;
|
||||||
for (const MipmapLevelInfo mli : mipinfos)
|
for (const MipmapLevelInfo mli : mipInfos)
|
||||||
{
|
{
|
||||||
D3D12_TEXTURE_COPY_LOCATION dst = {}, src = {};
|
D3D12_TEXTURE_COPY_LOCATION dst = {}, src = {};
|
||||||
dst.pResource = vramTexture;
|
dst.pResource = vramTexture;
|
||||||
dst.SubresourceIndex = miplevel;
|
dst.SubresourceIndex = (UINT)miplevel;
|
||||||
dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||||
src.PlacedFootprint.Offset = mli.offset;
|
src.PlacedFootprint.Offset = mli.offset;
|
||||||
src.pResource = Texture;
|
src.pResource = Texture;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue