1
0
mirror of https://github.com/microsoft/DirectXTex synced 2024-11-21 12:00:06 +00:00

ComputePitch now returns an HRESULT (#113)

This commit is contained in:
Chuck Walbourn 2018-08-03 16:49:30 -07:00 committed by GitHub
parent 3f8b8d36b9
commit 114a0acf6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 379 additions and 183 deletions

View File

@ -406,7 +406,7 @@ namespace
//--------------------------------------------------------------------------------------
// Get surface information for a particular format
//--------------------------------------------------------------------------------------
void GetSurfaceInfo(
HRESULT GetSurfaceInfo(
_In_ size_t width,
_In_ size_t height,
_In_ DXGI_FORMAT fmt,
@ -414,9 +414,9 @@ namespace
_Out_opt_ size_t* outRowBytes,
_Out_opt_ size_t* outNumRows)
{
size_t numBytes = 0;
size_t rowBytes = 0;
size_t numRows = 0;
uint64_t numBytes = 0;
uint64_t rowBytes = 0;
uint64_t numRows = 0;
bool bc = false;
bool packed = false;
@ -477,19 +477,22 @@ namespace
planar = true;
bpe = 4;
break;
default:
break;
}
if (bc)
{
size_t numBlocksWide = 0;
uint64_t numBlocksWide = 0;
if (width > 0)
{
numBlocksWide = std::max<size_t>(1, (width + 3) / 4);
numBlocksWide = std::max<uint64_t>(1u, (uint64_t(width) + 3u) / 4u);
}
size_t numBlocksHigh = 0;
uint64_t numBlocksHigh = 0;
if (height > 0)
{
numBlocksHigh = std::max<size_t>(1, (height + 3) / 4);
numBlocksHigh = std::max<uint64_t>(1u, (uint64_t(height) + 3u) / 4u);
}
rowBytes = numBlocksWide * bpe;
numRows = numBlocksHigh;
@ -497,42 +500,55 @@ namespace
}
else if (packed)
{
rowBytes = ((width + 1) >> 1) * bpe;
numRows = height;
rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;
numRows = uint64_t(height);
numBytes = rowBytes * height;
}
else if (fmt == DXGI_FORMAT_NV11)
{
rowBytes = ((width + 3) >> 2) * 4;
numRows = height * 2; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data
rowBytes = ((uint64_t(width) + 3u) >> 2) * 4u;
numRows = uint64_t(height) * 2u; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data
numBytes = rowBytes * numRows;
}
else if (planar)
{
rowBytes = ((width + 1) >> 1) * bpe;
numBytes = (rowBytes * height) + ((rowBytes * height + 1) >> 1);
numRows = height + ((height + 1) >> 1);
rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;
numBytes = (rowBytes * uint64_t(height)) + ((rowBytes * uint64_t(height) + 1u) >> 1);
numRows = height + ((uint64_t(height) + 1u) >> 1);
}
else
{
size_t bpp = BitsPerPixel(fmt);
rowBytes = (width * bpp + 7) / 8; // round up to nearest byte
numRows = height;
if (!bpp)
return E_INVALIDARG;
rowBytes = (uint64_t(width) * bpp + 7u) / 8u; // round up to nearest byte
numRows = uint64_t(height);
numBytes = rowBytes * height;
}
#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64)
static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!");
if (numBytes > UINT32_MAX || rowBytes > UINT32_MAX || numRows > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
#else
static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!");
#endif
if (outNumBytes)
{
*outNumBytes = numBytes;
*outNumBytes = static_cast<size_t>(numBytes);
}
if (outRowBytes)
{
*outRowBytes = rowBytes;
*outRowBytes = static_cast<size_t>(rowBytes);
}
if (outNumRows)
{
*outNumRows = numRows;
*outNumRows = static_cast<size_t>(numRows);
}
return S_OK;
}
@ -851,7 +867,9 @@ namespace
size_t d = depth;
for (size_t i = 0; i < mipCount; i++)
{
GetSurfaceInfo(w, h, format, &NumBytes, &RowBytes, nullptr);
HRESULT hr = GetSurfaceInfo(w, h, format, &NumBytes, &RowBytes, nullptr);
if (FAILED(hr))
return hr;
if (NumBytes > UINT32_MAX || RowBytes > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
@ -1357,7 +1375,9 @@ namespace
{
size_t numBytes = 0;
size_t rowBytes = 0;
GetSurfaceInfo(width, height, format, &numBytes, &rowBytes, nullptr);
hr = GetSurfaceInfo(width, height, format, &numBytes, &rowBytes, nullptr);
if (FAILED(hr))
return hr;
if (numBytes > bitSize)
{

View File

@ -336,6 +336,7 @@ namespace
case DXGI_FORMAT_P010:
case DXGI_FORMAT_P016:
case DXGI_FORMAT_V408:
return 24;
case DXGI_FORMAT_R8G8_TYPELESS:
@ -354,6 +355,8 @@ namespace
case DXGI_FORMAT_B5G5R5A1_UNORM:
case DXGI_FORMAT_A8P8:
case DXGI_FORMAT_B4G4R4A4_UNORM:
case DXGI_FORMAT_P208:
case DXGI_FORMAT_V208:
return 16;
case DXGI_FORMAT_NV12:
@ -409,17 +412,17 @@ namespace
//--------------------------------------------------------------------------------------
// Get surface information for a particular format
//--------------------------------------------------------------------------------------
void GetSurfaceInfo(
HRESULT GetSurfaceInfo(
_In_ size_t width,
_In_ size_t height,
_In_ DXGI_FORMAT fmt,
size_t* outNumBytes,
_Out_opt_ size_t* outRowBytes,
_Out_opt_ size_t* outNumRows )
_Out_opt_ size_t* outNumRows)
{
size_t numBytes = 0;
size_t rowBytes = 0;
size_t numRows = 0;
uint64_t numBytes = 0;
uint64_t rowBytes = 0;
uint64_t numRows = 0;
bool bc = false;
bool packed = false;
@ -433,7 +436,7 @@ namespace
case DXGI_FORMAT_BC4_TYPELESS:
case DXGI_FORMAT_BC4_UNORM:
case DXGI_FORMAT_BC4_SNORM:
bc=true;
bc = true;
bpe = 8;
break;
@ -471,6 +474,7 @@ namespace
case DXGI_FORMAT_NV12:
case DXGI_FORMAT_420_OPAQUE:
case DXGI_FORMAT_P208:
planar = true;
bpe = 2;
break;
@ -480,19 +484,22 @@ namespace
planar = true;
bpe = 4;
break;
default:
break;
}
if (bc)
{
size_t numBlocksWide = 0;
uint64_t numBlocksWide = 0;
if (width > 0)
{
numBlocksWide = std::max<size_t>( 1, (width + 3) / 4 );
numBlocksWide = std::max<uint64_t>(1u, (uint64_t(width) + 3u) / 4u);
}
size_t numBlocksHigh = 0;
uint64_t numBlocksHigh = 0;
if (height > 0)
{
numBlocksHigh = std::max<size_t>( 1, (height + 3) / 4 );
numBlocksHigh = std::max<uint64_t>(1u, (uint64_t(height) + 3u) / 4u);
}
rowBytes = numBlocksWide * bpe;
numRows = numBlocksHigh;
@ -500,42 +507,55 @@ namespace
}
else if (packed)
{
rowBytes = ( ( width + 1 ) >> 1 ) * bpe;
numRows = height;
rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;
numRows = uint64_t(height);
numBytes = rowBytes * height;
}
else if ( fmt == DXGI_FORMAT_NV11 )
else if (fmt == DXGI_FORMAT_NV11)
{
rowBytes = ( ( width + 3 ) >> 2 ) * 4;
numRows = height * 2; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data
rowBytes = ((uint64_t(width) + 3u) >> 2) * 4u;
numRows = uint64_t(height) * 2u; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data
numBytes = rowBytes * numRows;
}
else if (planar)
{
rowBytes = ( ( width + 1 ) >> 1 ) * bpe;
numBytes = ( rowBytes * height ) + ( ( rowBytes * height + 1 ) >> 1 );
numRows = height + ( ( height + 1 ) >> 1 );
rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;
numBytes = (rowBytes * uint64_t(height)) + ((rowBytes * uint64_t(height) + 1u) >> 1);
numRows = height + ((uint64_t(height) + 1u) >> 1);
}
else
{
size_t bpp = BitsPerPixel( fmt );
rowBytes = ( width * bpp + 7 ) / 8; // round up to nearest byte
numRows = height;
size_t bpp = BitsPerPixel(fmt);
if (!bpp)
return E_INVALIDARG;
rowBytes = (uint64_t(width) * bpp + 7u) / 8u; // round up to nearest byte
numRows = uint64_t(height);
numBytes = rowBytes * height;
}
#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64)
static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!");
if (numBytes > UINT32_MAX || rowBytes > UINT32_MAX || numRows > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
#else
static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!");
#endif
if (outNumBytes)
{
*outNumBytes = numBytes;
*outNumBytes = static_cast<size_t>(numBytes);
}
if (outRowBytes)
{
*outRowBytes = rowBytes;
*outRowBytes = static_cast<size_t>(rowBytes);
}
if (outNumRows)
{
*outNumRows = numRows;
*outNumRows = static_cast<size_t>(numRows);
}
return S_OK;
}
@ -849,12 +869,6 @@ namespace
case DXGI_FORMAT_NV12:
case DXGI_FORMAT_P010:
case DXGI_FORMAT_P016:
#if defined(_XBOX_ONE) && defined(_TITLE)
case DXGI_FORMAT_D16_UNORM_S8_UINT:
case DXGI_FORMAT_R16_UNORM_X8_TYPELESS:
case DXGI_FORMAT_X16_TYPELESS_G8_UINT:
#endif
if (!slicePlane)
{
// Plane 0
@ -930,7 +944,9 @@ namespace
size_t d = depth;
for (size_t i = 0; i < mipCount; i++)
{
GetSurfaceInfo(w, h, format, &NumBytes, &RowBytes, nullptr);
HRESULT hr = GetSurfaceInfo(w, h, format, &NumBytes, &RowBytes, nullptr);
if (FAILED(hr))
return hr;
if (NumBytes > UINT32_MAX || RowBytes > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);

View File

@ -71,7 +71,7 @@ namespace DirectX
CP_FLAGS_8BPP = 0x40000, // Override with a legacy 8 bits-per-pixel format size
};
void __cdecl ComputePitch(
HRESULT __cdecl ComputePitch(
_In_ DXGI_FORMAT fmt, _In_ size_t width, _In_ size_t height,
_Out_ size_t& rowPitch, _Out_ size_t& slicePitch, _In_ DWORD flags = CP_FLAGS_NONE);

View File

@ -686,7 +686,9 @@ HRESULT DirectX::_EncodeDDSHeader(
}
size_t rowPitch, slicePitch;
ComputePitch(metadata.format, metadata.width, metadata.height, rowPitch, slicePitch, CP_FLAGS_NONE);
HRESULT hr = ComputePitch(metadata.format, metadata.width, metadata.height, rowPitch, slicePitch, CP_FLAGS_NONE);
if (FAILED(hr))
return hr;
if (slicePitch > UINT32_MAX
|| rowPitch > UINT32_MAX)
@ -1140,7 +1142,9 @@ namespace
}
size_t pixelSize, nimages;
_DetermineImageArray(metadata, cpFlags, nimages, pixelSize);
if (!_DetermineImageArray(metadata, cpFlags, nimages, pixelSize))
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
if ((nimages == 0) || (nimages != image.GetImageCount()))
{
return E_FAIL;
@ -1741,6 +1745,12 @@ HRESULT DirectX::LoadFromDDSFile(
return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
}
if (image.GetPixelsSize() > UINT32_MAX)
{
image.Release();
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
}
if (!ReadFile(hFile.get(), image.GetPixels(), static_cast<DWORD>(image.GetPixelsSize()), &bytesRead, nullptr))
{
image.Release();
@ -1797,7 +1807,9 @@ HRESULT DirectX::SaveToDDSMemory(
return E_FAIL;
size_t ddsRowPitch, ddsSlicePitch;
ComputePitch(metadata.format, images[i].width, images[i].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE);
hr = ComputePitch(metadata.format, images[i].width, images[i].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE);
if (FAILED(hr))
return hr;
assert(images[i].rowPitch > 0);
assert(images[i].slicePitch > 0);
@ -1868,7 +1880,12 @@ HRESULT DirectX::SaveToDDSMemory(
else
{
size_t ddsRowPitch, ddsSlicePitch;
ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE);
hr = ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE);
if (FAILED(hr))
{
blob.Release();
return hr;
}
size_t rowPitch = images[index].rowPitch;
@ -1937,7 +1954,12 @@ HRESULT DirectX::SaveToDDSMemory(
else
{
size_t ddsRowPitch, ddsSlicePitch;
ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE);
hr = ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE);
if (FAILED(hr))
{
blob.Release();
return hr;
}
size_t rowPitch = images[index].rowPitch;
@ -2049,9 +2071,11 @@ HRESULT DirectX::SaveToDDSFile(
assert(images[index].slicePitch > 0);
size_t ddsRowPitch, ddsSlicePitch;
ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE);
hr = ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE);
if (FAILED(hr))
return hr;
if (images[index].slicePitch == ddsSlicePitch)
if ((images[index].slicePitch == ddsSlicePitch) && (ddsSlicePitch <= UINT32_MAX))
{
if (!WriteFile(hFile.get(), images[index].pixels, static_cast<DWORD>(ddsSlicePitch), &bytesWritten, nullptr))
{
@ -2072,6 +2096,9 @@ HRESULT DirectX::SaveToDDSFile(
return E_FAIL;
}
if (ddsRowPitch > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
const uint8_t * __restrict sPtr = images[index].pixels;
size_t lines = ComputeScanlines(metadata.format, images[index].height);
@ -2117,9 +2144,11 @@ HRESULT DirectX::SaveToDDSFile(
assert(images[index].slicePitch > 0);
size_t ddsRowPitch, ddsSlicePitch;
ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE);
hr = ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE);
if (FAILED(hr))
return hr;
if (images[index].slicePitch == ddsSlicePitch)
if ((images[index].slicePitch == ddsSlicePitch) && (ddsSlicePitch <= UINT32_MAX))
{
if (!WriteFile(hFile.get(), images[index].pixels, static_cast<DWORD>(ddsSlicePitch), &bytesWritten, nullptr))
{
@ -2140,6 +2169,9 @@ HRESULT DirectX::SaveToDDSFile(
return E_FAIL;
}
if (ddsRowPitch > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
const uint8_t * __restrict sPtr = images[index].pixels;
size_t lines = ComputeScanlines(metadata.format, images[index].height);

View File

@ -1011,8 +1011,13 @@ HRESULT DirectX::SaveToHDRFile(const Image& image, const wchar_t* szFile)
auto_delete_file delonfail(hFile.get());
size_t rowPitch = image.width * 4;
size_t slicePitch = image.height * rowPitch;
uint64_t pitch = uint64_t(image.width) * 4u;
uint64_t slicePitch = uint64_t(image.height) * pitch;
if (pitch > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
size_t rowPitch = static_cast<size_t>(pitch);
if (slicePitch < 65535)
{
@ -1088,6 +1093,9 @@ HRESULT DirectX::SaveToHDRFile(const Image& image, const wchar_t* szFile)
size_t encSize = EncodeRLE(enc, rgbe, rowPitch, image.width);
if (encSize > 0)
{
if (encSize > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
if (!WriteFile(hFile.get(), enc, static_cast<DWORD>(encSize), &bytesWritten, nullptr))
{
return HRESULT_FROM_WIN32(GetLastError());

View File

@ -24,7 +24,7 @@ using namespace DirectX;
// Determines number of image array entries and pixel size
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
void DirectX::_DetermineImageArray(
bool DirectX::_DetermineImageArray(
const TexMetadata& metadata,
DWORD cpFlags,
size_t& nImages,
@ -34,8 +34,8 @@ void DirectX::_DetermineImageArray(
assert(metadata.arraySize > 0);
assert(metadata.mipLevels > 0);
size_t _pixelSize = 0;
size_t _nimages = 0;
uint64_t totalPixelSize = 0;
size_t nimages = 0;
switch (metadata.dimension)
{
@ -49,10 +49,14 @@ void DirectX::_DetermineImageArray(
for (size_t level = 0; level < metadata.mipLevels; ++level)
{
size_t rowPitch, slicePitch;
ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags);
if (FAILED(ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags)))
{
nImages = pixelSize = 0;
return false;
}
_pixelSize += slicePitch;
++_nimages;
totalPixelSize += uint64_t(slicePitch);
++nimages;
if (h > 1)
h >>= 1;
@ -72,12 +76,16 @@ void DirectX::_DetermineImageArray(
for (size_t level = 0; level < metadata.mipLevels; ++level)
{
size_t rowPitch, slicePitch;
ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags);
if (FAILED(ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags)))
{
nImages = pixelSize = 0;
return false;
}
for (size_t slice = 0; slice < d; ++slice)
{
_pixelSize += slicePitch;
++_nimages;
totalPixelSize += uint64_t(slicePitch);
++nimages;
}
if (h > 1)
@ -93,12 +101,25 @@ void DirectX::_DetermineImageArray(
break;
default:
assert(false);
break;
nImages = pixelSize = 0;
return false;
}
nImages = _nimages;
pixelSize = _pixelSize;
#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64)
static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!");
if (totalPixelSize > UINT32_MAX)
{
nImages = pixelSize = 0;
return false;
}
#else
static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!");
#endif
nImages = nimages;
pixelSize = static_cast<size_t>(totalPixelSize);
return true;
}
@ -147,7 +168,8 @@ bool DirectX::_SetupImageArray(
}
size_t rowPitch, slicePitch;
ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags);
if (FAILED(ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags)))
return false;
images[index].width = w;
images[index].height = h;
@ -186,7 +208,8 @@ bool DirectX::_SetupImageArray(
for (size_t level = 0; level < metadata.mipLevels; ++level)
{
size_t rowPitch, slicePitch;
ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags);
if (FAILED(ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags)))
return false;
for (size_t slice = 0; slice < d; ++slice)
{
@ -318,7 +341,8 @@ HRESULT ScratchImage::Initialize(const TexMetadata& mdata, DWORD flags)
m_metadata.dimension = mdata.dimension;
size_t pixelSize, nimages;
_DetermineImageArray(m_metadata, flags, nimages, pixelSize);
if (!_DetermineImageArray(m_metadata, flags, nimages, pixelSize))
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
m_image = new (std::nothrow) Image[nimages];
if (!m_image)
@ -384,7 +408,8 @@ HRESULT ScratchImage::Initialize2D(DXGI_FORMAT fmt, size_t width, size_t height,
m_metadata.dimension = TEX_DIMENSION_TEXTURE2D;
size_t pixelSize, nimages;
_DetermineImageArray(m_metadata, flags, nimages, pixelSize);
if (!_DetermineImageArray(m_metadata, flags, nimages, pixelSize))
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
m_image = new (std::nothrow) Image[nimages];
if (!m_image)
@ -434,7 +459,8 @@ HRESULT ScratchImage::Initialize3D(DXGI_FORMAT fmt, size_t width, size_t height,
m_metadata.dimension = TEX_DIMENSION_TEXTURE3D;
size_t pixelSize, nimages;
_DetermineImageArray(m_metadata, flags, nimages, pixelSize);
if (!_DetermineImageArray(m_metadata, flags, nimages, pixelSize))
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
m_image = new (std::nothrow) Image[nimages];
if (!m_image)

View File

@ -178,7 +178,7 @@ namespace DirectX
//---------------------------------------------------------------------------------
// Image helper functions
void __cdecl _DetermineImageArray(
_Success_(return != false) bool __cdecl _DetermineImageArray(
_In_ const TexMetadata& metadata, _In_ DWORD cpFlags,
_Out_ size_t& nImages, _Out_ size_t& pixelSize);

View File

@ -272,7 +272,9 @@ namespace
else
{
size_t slicePitch;
ComputePitch(image->format, image->width, image->height, rowPitch, slicePitch, CP_FLAGS_NONE);
HRESULT hr = ComputePitch(image->format, image->width, image->height, rowPitch, slicePitch, CP_FLAGS_NONE);
if (FAILED(hr))
return hr;
}
auto sPtr = static_cast<const uint8_t*>(pSource);
@ -596,7 +598,9 @@ namespace
else
{
size_t slicePitch;
ComputePitch(image->format, image->width, image->height, rowPitch, slicePitch, CP_FLAGS_NONE);
HRESULT hr = ComputePitch(image->format, image->width, image->height, rowPitch, slicePitch, CP_FLAGS_NONE);
if (FAILED(hr))
return hr;
}
auto sPtr = static_cast<const uint8_t*>(pSource);
@ -1050,6 +1054,18 @@ HRESULT DirectX::LoadFromTGAFile(
if (!(convFlags & (CONV_FLAGS_RLE | CONV_FLAGS_EXPAND | CONV_FLAGS_INVERTX)) && (convFlags & CONV_FLAGS_INVERTY))
{
// This case we can read directly into the image buffer in place
if (remaining < image.GetPixelsSize())
{
image.Release();
return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
}
if (image.GetPixelsSize() > UINT32_MAX)
{
image.Release();
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
}
if (!ReadFile(hFile.get(), image.GetPixels(), static_cast<DWORD>(image.GetPixelsSize()), &bytesRead, nullptr))
{
image.Release();
@ -1253,7 +1269,9 @@ HRESULT DirectX::SaveToTGAMemory(const Image& image, Blob& blob)
}
else
{
ComputePitch(image.format, image.width, image.height, rowPitch, slicePitch, CP_FLAGS_NONE);
hr = ComputePitch(image.format, image.width, image.height, rowPitch, slicePitch, CP_FLAGS_NONE);
if (FAILED(hr))
return hr;
}
hr = blob.Initialize(sizeof(TGA_HEADER) + slicePitch);
@ -1328,12 +1346,25 @@ HRESULT DirectX::SaveToTGAFile(const Image& image, const wchar_t* szFile)
size_t rowPitch, slicePitch;
if (convFlags & CONV_FLAGS_888)
{
rowPitch = image.width * 3;
slicePitch = image.height * rowPitch;
uint64_t pitch = uint64_t(image.width) * 3u;
uint64_t slice = uint64_t(image.height) * pitch;
#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64)
static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!");
if (pitch > UINT32_MAX || slice > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
#else
static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!");
#endif
rowPitch = static_cast<size_t>(pitch);
slicePitch = static_cast<size_t>(slice);
}
else
{
ComputePitch(image.format, image.width, image.height, rowPitch, slicePitch, CP_FLAGS_NONE);
hr = ComputePitch(image.format, image.width, image.height, rowPitch, slicePitch, CP_FLAGS_NONE);
if (FAILED(hr))
return hr;
}
if (slicePitch < 65535)
@ -1375,6 +1406,9 @@ HRESULT DirectX::SaveToTGAFile(const Image& image, const wchar_t* szFile)
if (bytesWritten != sizeof(TGA_HEADER))
return E_FAIL;
if (rowPitch > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
// Write pixels
const uint8_t* pPixels = image.pixels;

View File

@ -870,9 +870,12 @@ size_t DirectX::BitsPerColor(DXGI_FORMAT fmt)
// based on DXGI format, width, and height
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
void DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height,
HRESULT DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height,
size_t& rowPitch, size_t& slicePitch, DWORD flags)
{
uint64_t pitch = 0;
uint64_t slice = 0;
switch (static_cast<int>(fmt))
{
case DXGI_FORMAT_BC1_TYPELESS:
@ -887,15 +890,15 @@ void DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height,
{
size_t nbw = width >> 2;
size_t nbh = height >> 2;
rowPitch = std::max<size_t>(1, nbw * 8);
slicePitch = std::max<size_t>(1, rowPitch * nbh);
pitch = std::max<uint64_t>(1u, uint64_t(nbw) * 8u);
slice = std::max<uint64_t>(1u, pitch * uint64_t(nbh));
}
else
{
size_t nbw = std::max<size_t>(1, (width + 3) / 4);
size_t nbh = std::max<size_t>(1, (height + 3) / 4);
rowPitch = nbw * 8;
slicePitch = rowPitch * nbh;
uint64_t nbw = std::max<uint64_t>(1u, (uint64_t(width) + 3u) / 4u);
uint64_t nbh = std::max<uint64_t>(1u, (uint64_t(height) + 3u) / 4u);
pitch = nbw * 8u;
slice = pitch * nbh;
}
}
break;
@ -921,15 +924,15 @@ void DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height,
{
size_t nbw = width >> 2;
size_t nbh = height >> 2;
rowPitch = std::max<size_t>(1, nbw * 16);
slicePitch = std::max<size_t>(1, rowPitch * nbh);
pitch = std::max<uint64_t>(1u, uint64_t(nbw) * 16u);
slice = std::max<uint64_t>(1u, pitch * uint64_t(nbh));
}
else
{
size_t nbw = std::max<size_t>(1, (width + 3) / 4);
size_t nbh = std::max<size_t>(1, (height + 3) / 4);
rowPitch = nbw * 16;
slicePitch = rowPitch * nbh;
uint64_t nbw = std::max<uint64_t>(1u, (uint64_t(width) + 3u) / 4u);
uint64_t nbh = std::max<uint64_t>(1u, (uint64_t(height) + 3u) / 4u);
pitch = nbw * 16u;
slice = pitch * nbh;
}
}
break;
@ -938,22 +941,22 @@ void DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height,
case DXGI_FORMAT_G8R8_G8B8_UNORM:
case DXGI_FORMAT_YUY2:
assert(IsPacked(fmt));
rowPitch = ((width + 1) >> 1) * 4;
slicePitch = rowPitch * height;
pitch = ((uint64_t(width) + 1u) >> 1) * 4u;
slice = pitch * uint64_t(height);
break;
case DXGI_FORMAT_Y210:
case DXGI_FORMAT_Y216:
assert(IsPacked(fmt));
rowPitch = ((width + 1) >> 1) * 8;
slicePitch = rowPitch * height;
pitch = ((uint64_t(width) + 1u) >> 1) * 8u;
slice = pitch * uint64_t(height);
break;
case DXGI_FORMAT_NV12:
case DXGI_FORMAT_420_OPAQUE:
assert(IsPlanar(fmt));
rowPitch = ((width + 1) >> 1) * 2;
slicePitch = rowPitch * (height + ((height + 1) >> 1));
pitch = ((uint64_t(width) + 1u) >> 1) * 2u;
slice = pitch * (uint64_t(height) + ((uint64_t(height) + 1u) >> 1));
break;
case DXGI_FORMAT_P010:
@ -962,39 +965,37 @@ void DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height,
case XBOX_DXGI_FORMAT_R16_UNORM_X8_TYPELESS:
case XBOX_DXGI_FORMAT_X16_TYPELESS_G8_UINT:
assert(IsPlanar(fmt));
rowPitch = ((width + 1) >> 1) * 4;
slicePitch = rowPitch * (height + ((height + 1) >> 1));
pitch = ((uint64_t(width) + 1u) >> 1) * 4u;
slice = pitch * (uint64_t(height) + ((uint64_t(height) + 1u) >> 1));
break;
case DXGI_FORMAT_NV11:
assert(IsPlanar(fmt));
rowPitch = ((width + 3) >> 2) * 4;
slicePitch = rowPitch * height * 2;
pitch = ((uint64_t(width) + 3u) >> 2) * 4u;
slice = pitch * uint64_t(height) * 2u;
break;
case WIN10_DXGI_FORMAT_P208:
assert(IsPlanar(fmt));
rowPitch = ((width + 1) >> 1) * 2;
slicePitch = rowPitch * height * 2;
pitch = ((uint64_t(width) + 1u) >> 1) * 2u;
slice = pitch * uint64_t(height) * 2u;
break;
case WIN10_DXGI_FORMAT_V208:
assert(IsPlanar(fmt));
rowPitch = width;
slicePitch = rowPitch * (height + (((height + 1) >> 1) * 2));
pitch = uint64_t(width);
slice = pitch * (uint64_t(height) + (((uint64_t(height) + 1u) >> 1) * 2u));
break;
case WIN10_DXGI_FORMAT_V408:
assert(IsPlanar(fmt));
rowPitch = width;
slicePitch = rowPitch * (height + ((height >> 1) * 4));
pitch = uint64_t(width);
slice = pitch * (uint64_t(height) + (uint64_t(height >> 1) * 4u));
break;
default:
assert(IsValid(fmt));
assert(!IsCompressed(fmt) && !IsPacked(fmt) && !IsPlanar(fmt));
{
size_t bpp;
if (flags & CP_FLAGS_24BPP)
@ -1006,45 +1007,64 @@ void DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height,
else
bpp = BitsPerPixel(fmt);
if (!bpp)
return E_INVALIDARG;
if (flags & (CP_FLAGS_LEGACY_DWORD | CP_FLAGS_PARAGRAPH | CP_FLAGS_YMM | CP_FLAGS_ZMM | CP_FLAGS_PAGE4K))
{
if (flags & CP_FLAGS_PAGE4K)
{
rowPitch = ((width * bpp + 32767) / 32768) * 4096;
slicePitch = rowPitch * height;
pitch = ((uint64_t(width) * bpp + 32767u) / 32768u) * 4096u;
slice = pitch * uint64_t(height);
}
else if (flags & CP_FLAGS_ZMM)
{
rowPitch = ((width * bpp + 511) / 512) * 64;
slicePitch = rowPitch * height;
pitch = ((uint64_t(width) * bpp + 511u) / 512u) * 64u;
slice = pitch * uint64_t(height);
}
else if (flags & CP_FLAGS_YMM)
{
rowPitch = ((width * bpp + 255) / 256) * 32;
slicePitch = rowPitch * height;
pitch = ((uint64_t(width) * bpp + 255u) / 256u) * 32u;
slice = pitch * uint64_t(height);
}
else if (flags & CP_FLAGS_PARAGRAPH)
{
rowPitch = ((width * bpp + 127) / 128) * 16;
slicePitch = rowPitch * height;
pitch = ((uint64_t(width) * bpp + 127u) / 128u) * 16u;
slice = pitch * uint64_t(height);
}
else // DWORD alignment
{
// Special computation for some incorrectly created DDS files based on
// legacy DirectDraw assumptions about pitch alignment
rowPitch = ((width * bpp + 31) / 32) * sizeof(uint32_t);
slicePitch = rowPitch * height;
pitch = ((uint64_t(width) * bpp + 31u) / 32u) * sizeof(uint32_t);
slice = pitch * uint64_t(height);
}
}
else
{
// Default byte alignment
rowPitch = (width * bpp + 7) / 8;
slicePitch = rowPitch * height;
pitch = (uint64_t(width) * bpp + 7u) / 8u;
slice = pitch * uint64_t(height);
}
}
break;
}
#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64)
static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!");
if (pitch > UINT32_MAX || slice > UINT32_MAX)
{
rowPitch = slicePitch = 0;
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
}
#else
static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!");
#endif
rowPitch = static_cast<size_t>(pitch);
slicePitch = static_cast<size_t>(slice);
return S_OK;
}

View File

@ -434,17 +434,17 @@ namespace
//--------------------------------------------------------------------------------------
// Get surface information for a particular format
//--------------------------------------------------------------------------------------
void GetSurfaceInfo(
HRESULT GetSurfaceInfo(
_In_ size_t width,
_In_ size_t height,
_In_ DXGI_FORMAT fmt,
_Out_opt_ size_t* outNumBytes,
_Out_opt_ size_t* outRowBytes,
_Out_opt_ size_t* outNumRows )
_Out_opt_ size_t* outNumRows)
{
size_t numBytes = 0;
size_t rowBytes = 0;
size_t numRows = 0;
uint64_t numBytes = 0;
uint64_t rowBytes = 0;
uint64_t numRows = 0;
bool bc = false;
bool packed = false;
@ -458,7 +458,7 @@ namespace
case DXGI_FORMAT_BC4_TYPELESS:
case DXGI_FORMAT_BC4_UNORM:
case DXGI_FORMAT_BC4_SNORM:
bc=true;
bc = true;
bpe = 8;
break;
@ -505,19 +505,22 @@ namespace
planar = true;
bpe = 4;
break;
default:
break;
}
if (bc)
{
size_t numBlocksWide = 0;
uint64_t numBlocksWide = 0;
if (width > 0)
{
numBlocksWide = std::max<size_t>( 1, (width + 3) / 4 );
numBlocksWide = std::max<uint64_t>(1u, (uint64_t(width) + 3u) / 4u);
}
size_t numBlocksHigh = 0;
uint64_t numBlocksHigh = 0;
if (height > 0)
{
numBlocksHigh = std::max<size_t>( 1, (height + 3) / 4 );
numBlocksHigh = std::max<uint64_t>(1u, (uint64_t(height) + 3u) / 4u);
}
rowBytes = numBlocksWide * bpe;
numRows = numBlocksHigh;
@ -525,42 +528,55 @@ namespace
}
else if (packed)
{
rowBytes = ( ( width + 1 ) >> 1 ) * bpe;
numRows = height;
rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;
numRows = uint64_t(height);
numBytes = rowBytes * height;
}
else if ( fmt == DXGI_FORMAT_NV11 )
else if (fmt == DXGI_FORMAT_NV11)
{
rowBytes = ( ( width + 3 ) >> 2 ) * 4;
numRows = height * 2; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data
rowBytes = ((uint64_t(width) + 3u) >> 2) * 4u;
numRows = uint64_t(height) * 2u; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data
numBytes = rowBytes * numRows;
}
else if (planar)
{
rowBytes = ( ( width + 1 ) >> 1 ) * bpe;
numBytes = ( rowBytes * height ) + ( ( rowBytes * height + 1 ) >> 1 );
numRows = height + ( ( height + 1 ) >> 1 );
rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;
numBytes = (rowBytes * uint64_t(height)) + ((rowBytes * uint64_t(height) + 1u) >> 1);
numRows = height + ((uint64_t(height) + 1u) >> 1);
}
else
{
size_t bpp = BitsPerPixel( fmt );
rowBytes = ( width * bpp + 7 ) / 8; // round up to nearest byte
numRows = height;
size_t bpp = BitsPerPixel(fmt);
if (!bpp)
return E_INVALIDARG;
rowBytes = (uint64_t(width) * bpp + 7u) / 8u; // round up to nearest byte
numRows = uint64_t(height);
numBytes = rowBytes * height;
}
#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64)
static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!");
if (numBytes > UINT32_MAX || rowBytes > UINT32_MAX || numRows > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
#else
static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!");
#endif
if (outNumBytes)
{
*outNumBytes = numBytes;
*outNumBytes = static_cast<size_t>(numBytes);
}
if (outRowBytes)
{
*outRowBytes = rowBytes;
*outRowBytes = static_cast<size_t>(rowBytes);
}
if (outNumRows)
{
*outNumRows = numRows;
*outNumRows = static_cast<size_t>(numRows);
}
return S_OK;
}
@ -845,7 +861,9 @@ HRESULT DirectX::SaveDDSTextureToFile(
}
size_t rowPitch, slicePitch, rowCount;
GetSurfaceInfo( desc.Width, desc.Height, desc.Format, &slicePitch, &rowPitch, &rowCount );
hr = GetSurfaceInfo( desc.Width, desc.Height, desc.Format, &slicePitch, &rowPitch, &rowCount );
if (FAILED(hr))
return hr;
if (rowPitch > UINT32_MAX || slicePitch > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);

View File

@ -325,6 +325,7 @@ namespace
case DXGI_FORMAT_P010:
case DXGI_FORMAT_P016:
case DXGI_FORMAT_V408:
return 24;
case DXGI_FORMAT_R8G8_TYPELESS:
@ -343,6 +344,8 @@ namespace
case DXGI_FORMAT_B5G5R5A1_UNORM:
case DXGI_FORMAT_A8P8:
case DXGI_FORMAT_B4G4R4A4_UNORM:
case DXGI_FORMAT_P208:
case DXGI_FORMAT_V208:
return 16;
case DXGI_FORMAT_NV12:
@ -434,17 +437,17 @@ namespace
//--------------------------------------------------------------------------------------
// Get surface information for a particular format
//--------------------------------------------------------------------------------------
void GetSurfaceInfo(
HRESULT GetSurfaceInfo(
_In_ size_t width,
_In_ size_t height,
_In_ DXGI_FORMAT fmt,
_Out_opt_ size_t* outNumBytes,
_Out_opt_ size_t* outRowBytes,
_Out_opt_ size_t* outNumRows )
_Out_opt_ size_t* outNumRows)
{
size_t numBytes = 0;
size_t rowBytes = 0;
size_t numRows = 0;
uint64_t numBytes = 0;
uint64_t rowBytes = 0;
uint64_t numRows = 0;
bool bc = false;
bool packed = false;
@ -458,7 +461,7 @@ namespace
case DXGI_FORMAT_BC4_TYPELESS:
case DXGI_FORMAT_BC4_UNORM:
case DXGI_FORMAT_BC4_SNORM:
bc=true;
bc = true;
bpe = 8;
break;
@ -496,6 +499,7 @@ namespace
case DXGI_FORMAT_NV12:
case DXGI_FORMAT_420_OPAQUE:
case DXGI_FORMAT_P208:
planar = true;
bpe = 2;
break;
@ -505,19 +509,22 @@ namespace
planar = true;
bpe = 4;
break;
default:
break;
}
if (bc)
{
size_t numBlocksWide = 0;
uint64_t numBlocksWide = 0;
if (width > 0)
{
numBlocksWide = std::max<size_t>( 1, (width + 3) / 4 );
numBlocksWide = std::max<uint64_t>(1u, (uint64_t(width) + 3u) / 4u);
}
size_t numBlocksHigh = 0;
uint64_t numBlocksHigh = 0;
if (height > 0)
{
numBlocksHigh = std::max<size_t>( 1, (height + 3) / 4 );
numBlocksHigh = std::max<uint64_t>(1u, (uint64_t(height) + 3u) / 4u);
}
rowBytes = numBlocksWide * bpe;
numRows = numBlocksHigh;
@ -525,42 +532,55 @@ namespace
}
else if (packed)
{
rowBytes = ( ( width + 1 ) >> 1 ) * bpe;
numRows = height;
rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;
numRows = uint64_t(height);
numBytes = rowBytes * height;
}
else if ( fmt == DXGI_FORMAT_NV11 )
else if (fmt == DXGI_FORMAT_NV11)
{
rowBytes = ( ( width + 3 ) >> 2 ) * 4;
numRows = height * 2; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data
rowBytes = ((uint64_t(width) + 3u) >> 2) * 4u;
numRows = uint64_t(height) * 2u; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data
numBytes = rowBytes * numRows;
}
else if (planar)
{
rowBytes = ( ( width + 1 ) >> 1 ) * bpe;
numBytes = ( rowBytes * height ) + ( ( rowBytes * height + 1 ) >> 1 );
numRows = height + ( ( height + 1 ) >> 1 );
rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;
numBytes = (rowBytes * uint64_t(height)) + ((rowBytes * uint64_t(height) + 1u) >> 1);
numRows = height + ((uint64_t(height) + 1u) >> 1);
}
else
{
size_t bpp = BitsPerPixel( fmt );
rowBytes = ( width * bpp + 7 ) / 8; // round up to nearest byte
numRows = height;
size_t bpp = BitsPerPixel(fmt);
if (!bpp)
return E_INVALIDARG;
rowBytes = (uint64_t(width) * bpp + 7u) / 8u; // round up to nearest byte
numRows = uint64_t(height);
numBytes = rowBytes * height;
}
#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64)
static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!");
if (numBytes > UINT32_MAX || rowBytes > UINT32_MAX || numRows > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
#else
static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!");
#endif
if (outNumBytes)
{
*outNumBytes = numBytes;
*outNumBytes = static_cast<size_t>(numBytes);
}
if (outRowBytes)
{
*outRowBytes = rowBytes;
*outRowBytes = static_cast<size_t>(rowBytes);
}
if (outNumRows)
{
*outNumRows = numRows;
*outNumRows = static_cast<size_t>(numRows);
}
return S_OK;
}
@ -934,7 +954,9 @@ HRESULT DirectX::SaveDDSTextureToFile(
}
size_t rowPitch, slicePitch, rowCount;
GetSurfaceInfo(static_cast<size_t>(desc.Width), desc.Height, desc.Format, &slicePitch, &rowPitch, &rowCount);
hr = GetSurfaceInfo(static_cast<size_t>(desc.Width), desc.Height, desc.Format, &slicePitch, &rowPitch, &rowCount);
if (FAILED(hr))
return hr;
if (rowPitch > UINT32_MAX || slicePitch > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);