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

View File

@ -336,6 +336,7 @@ namespace
case DXGI_FORMAT_P010: case DXGI_FORMAT_P010:
case DXGI_FORMAT_P016: case DXGI_FORMAT_P016:
case DXGI_FORMAT_V408:
return 24; return 24;
case DXGI_FORMAT_R8G8_TYPELESS: case DXGI_FORMAT_R8G8_TYPELESS:
@ -354,6 +355,8 @@ namespace
case DXGI_FORMAT_B5G5R5A1_UNORM: case DXGI_FORMAT_B5G5R5A1_UNORM:
case DXGI_FORMAT_A8P8: case DXGI_FORMAT_A8P8:
case DXGI_FORMAT_B4G4R4A4_UNORM: case DXGI_FORMAT_B4G4R4A4_UNORM:
case DXGI_FORMAT_P208:
case DXGI_FORMAT_V208:
return 16; return 16;
case DXGI_FORMAT_NV12: case DXGI_FORMAT_NV12:
@ -409,17 +412,17 @@ namespace
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
// Get surface information for a particular format // Get surface information for a particular format
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
void GetSurfaceInfo( HRESULT GetSurfaceInfo(
_In_ size_t width, _In_ size_t width,
_In_ size_t height, _In_ size_t height,
_In_ DXGI_FORMAT fmt, _In_ DXGI_FORMAT fmt,
size_t* outNumBytes, size_t* outNumBytes,
_Out_opt_ size_t* outRowBytes, _Out_opt_ size_t* outRowBytes,
_Out_opt_ size_t* outNumRows ) _Out_opt_ size_t* outNumRows)
{ {
size_t numBytes = 0; uint64_t numBytes = 0;
size_t rowBytes = 0; uint64_t rowBytes = 0;
size_t numRows = 0; uint64_t numRows = 0;
bool bc = false; bool bc = false;
bool packed = false; bool packed = false;
@ -433,7 +436,7 @@ namespace
case DXGI_FORMAT_BC4_TYPELESS: case DXGI_FORMAT_BC4_TYPELESS:
case DXGI_FORMAT_BC4_UNORM: case DXGI_FORMAT_BC4_UNORM:
case DXGI_FORMAT_BC4_SNORM: case DXGI_FORMAT_BC4_SNORM:
bc=true; bc = true;
bpe = 8; bpe = 8;
break; break;
@ -471,6 +474,7 @@ namespace
case DXGI_FORMAT_NV12: case DXGI_FORMAT_NV12:
case DXGI_FORMAT_420_OPAQUE: case DXGI_FORMAT_420_OPAQUE:
case DXGI_FORMAT_P208:
planar = true; planar = true;
bpe = 2; bpe = 2;
break; break;
@ -480,19 +484,22 @@ namespace
planar = true; planar = true;
bpe = 4; bpe = 4;
break; break;
default:
break;
} }
if (bc) if (bc)
{ {
size_t numBlocksWide = 0; uint64_t numBlocksWide = 0;
if (width > 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) 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; rowBytes = numBlocksWide * bpe;
numRows = numBlocksHigh; numRows = numBlocksHigh;
@ -500,42 +507,55 @@ namespace
} }
else if (packed) else if (packed)
{ {
rowBytes = ( ( width + 1 ) >> 1 ) * bpe; rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;
numRows = height; numRows = uint64_t(height);
numBytes = rowBytes * height; numBytes = rowBytes * height;
} }
else if ( fmt == DXGI_FORMAT_NV11 ) else if (fmt == DXGI_FORMAT_NV11)
{ {
rowBytes = ( ( width + 3 ) >> 2 ) * 4; rowBytes = ((uint64_t(width) + 3u) >> 2) * 4u;
numRows = height * 2; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data numRows = uint64_t(height) * 2u; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data
numBytes = rowBytes * numRows; numBytes = rowBytes * numRows;
} }
else if (planar) else if (planar)
{ {
rowBytes = ( ( width + 1 ) >> 1 ) * bpe; rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;
numBytes = ( rowBytes * height ) + ( ( rowBytes * height + 1 ) >> 1 ); numBytes = (rowBytes * uint64_t(height)) + ((rowBytes * uint64_t(height) + 1u) >> 1);
numRows = height + ( ( height + 1 ) >> 1 ); numRows = height + ((uint64_t(height) + 1u) >> 1);
} }
else else
{ {
size_t bpp = BitsPerPixel( fmt ); size_t bpp = BitsPerPixel(fmt);
rowBytes = ( width * bpp + 7 ) / 8; // round up to nearest byte if (!bpp)
numRows = height; return E_INVALIDARG;
rowBytes = (uint64_t(width) * bpp + 7u) / 8u; // round up to nearest byte
numRows = uint64_t(height);
numBytes = rowBytes * 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) if (outNumBytes)
{ {
*outNumBytes = numBytes; *outNumBytes = static_cast<size_t>(numBytes);
} }
if (outRowBytes) if (outRowBytes)
{ {
*outRowBytes = rowBytes; *outRowBytes = static_cast<size_t>(rowBytes);
} }
if (outNumRows) 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_NV12:
case DXGI_FORMAT_P010: case DXGI_FORMAT_P010:
case DXGI_FORMAT_P016: 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) if (!slicePlane)
{ {
// Plane 0 // Plane 0
@ -930,7 +944,9 @@ namespace
size_t d = depth; size_t d = depth;
for (size_t i = 0; i < mipCount; i++) 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) if (NumBytes > UINT32_MAX || RowBytes > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); 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 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, _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); _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; 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 if (slicePitch > UINT32_MAX
|| rowPitch > UINT32_MAX) || rowPitch > UINT32_MAX)
@ -1140,7 +1142,9 @@ namespace
} }
size_t pixelSize, nimages; 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())) if ((nimages == 0) || (nimages != image.GetImageCount()))
{ {
return E_FAIL; return E_FAIL;
@ -1741,6 +1745,12 @@ HRESULT DirectX::LoadFromDDSFile(
return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF); 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)) if (!ReadFile(hFile.get(), image.GetPixels(), static_cast<DWORD>(image.GetPixelsSize()), &bytesRead, nullptr))
{ {
image.Release(); image.Release();
@ -1797,7 +1807,9 @@ HRESULT DirectX::SaveToDDSMemory(
return E_FAIL; return E_FAIL;
size_t ddsRowPitch, ddsSlicePitch; 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].rowPitch > 0);
assert(images[i].slicePitch > 0); assert(images[i].slicePitch > 0);
@ -1868,7 +1880,12 @@ HRESULT DirectX::SaveToDDSMemory(
else else
{ {
size_t ddsRowPitch, ddsSlicePitch; 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; size_t rowPitch = images[index].rowPitch;
@ -1937,7 +1954,12 @@ HRESULT DirectX::SaveToDDSMemory(
else else
{ {
size_t ddsRowPitch, ddsSlicePitch; 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; size_t rowPitch = images[index].rowPitch;
@ -2049,9 +2071,11 @@ HRESULT DirectX::SaveToDDSFile(
assert(images[index].slicePitch > 0); assert(images[index].slicePitch > 0);
size_t ddsRowPitch, ddsSlicePitch; 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)) if (!WriteFile(hFile.get(), images[index].pixels, static_cast<DWORD>(ddsSlicePitch), &bytesWritten, nullptr))
{ {
@ -2072,6 +2096,9 @@ HRESULT DirectX::SaveToDDSFile(
return E_FAIL; return E_FAIL;
} }
if (ddsRowPitch > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
const uint8_t * __restrict sPtr = images[index].pixels; const uint8_t * __restrict sPtr = images[index].pixels;
size_t lines = ComputeScanlines(metadata.format, images[index].height); size_t lines = ComputeScanlines(metadata.format, images[index].height);
@ -2117,9 +2144,11 @@ HRESULT DirectX::SaveToDDSFile(
assert(images[index].slicePitch > 0); assert(images[index].slicePitch > 0);
size_t ddsRowPitch, ddsSlicePitch; 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)) if (!WriteFile(hFile.get(), images[index].pixels, static_cast<DWORD>(ddsSlicePitch), &bytesWritten, nullptr))
{ {
@ -2140,6 +2169,9 @@ HRESULT DirectX::SaveToDDSFile(
return E_FAIL; return E_FAIL;
} }
if (ddsRowPitch > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
const uint8_t * __restrict sPtr = images[index].pixels; const uint8_t * __restrict sPtr = images[index].pixels;
size_t lines = ComputeScanlines(metadata.format, images[index].height); 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()); auto_delete_file delonfail(hFile.get());
size_t rowPitch = image.width * 4; uint64_t pitch = uint64_t(image.width) * 4u;
size_t slicePitch = image.height * rowPitch; 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) 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); size_t encSize = EncodeRLE(enc, rgbe, rowPitch, image.width);
if (encSize > 0) 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)) if (!WriteFile(hFile.get(), enc, static_cast<DWORD>(encSize), &bytesWritten, nullptr))
{ {
return HRESULT_FROM_WIN32(GetLastError()); return HRESULT_FROM_WIN32(GetLastError());

View File

@ -24,7 +24,7 @@ using namespace DirectX;
// Determines number of image array entries and pixel size // Determines number of image array entries and pixel size
//------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------
_Use_decl_annotations_ _Use_decl_annotations_
void DirectX::_DetermineImageArray( bool DirectX::_DetermineImageArray(
const TexMetadata& metadata, const TexMetadata& metadata,
DWORD cpFlags, DWORD cpFlags,
size_t& nImages, size_t& nImages,
@ -34,8 +34,8 @@ void DirectX::_DetermineImageArray(
assert(metadata.arraySize > 0); assert(metadata.arraySize > 0);
assert(metadata.mipLevels > 0); assert(metadata.mipLevels > 0);
size_t _pixelSize = 0; uint64_t totalPixelSize = 0;
size_t _nimages = 0; size_t nimages = 0;
switch (metadata.dimension) switch (metadata.dimension)
{ {
@ -49,10 +49,14 @@ void DirectX::_DetermineImageArray(
for (size_t level = 0; level < metadata.mipLevels; ++level) for (size_t level = 0; level < metadata.mipLevels; ++level)
{ {
size_t rowPitch, slicePitch; 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; totalPixelSize += uint64_t(slicePitch);
++_nimages; ++nimages;
if (h > 1) if (h > 1)
h >>= 1; h >>= 1;
@ -72,12 +76,16 @@ void DirectX::_DetermineImageArray(
for (size_t level = 0; level < metadata.mipLevels; ++level) for (size_t level = 0; level < metadata.mipLevels; ++level)
{ {
size_t rowPitch, slicePitch; 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) for (size_t slice = 0; slice < d; ++slice)
{ {
_pixelSize += slicePitch; totalPixelSize += uint64_t(slicePitch);
++_nimages; ++nimages;
} }
if (h > 1) if (h > 1)
@ -93,12 +101,25 @@ void DirectX::_DetermineImageArray(
break; break;
default: default:
assert(false); nImages = pixelSize = 0;
break; return false;
} }
nImages = _nimages; #if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64)
pixelSize = _pixelSize; 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; 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].width = w;
images[index].height = h; images[index].height = h;
@ -186,7 +208,8 @@ bool DirectX::_SetupImageArray(
for (size_t level = 0; level < metadata.mipLevels; ++level) for (size_t level = 0; level < metadata.mipLevels; ++level)
{ {
size_t rowPitch, slicePitch; 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) 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; m_metadata.dimension = mdata.dimension;
size_t pixelSize, nimages; 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]; m_image = new (std::nothrow) Image[nimages];
if (!m_image) 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; m_metadata.dimension = TEX_DIMENSION_TEXTURE2D;
size_t pixelSize, nimages; 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]; m_image = new (std::nothrow) Image[nimages];
if (!m_image) 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; m_metadata.dimension = TEX_DIMENSION_TEXTURE3D;
size_t pixelSize, nimages; 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]; m_image = new (std::nothrow) Image[nimages];
if (!m_image) if (!m_image)

View File

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

View File

@ -272,7 +272,9 @@ namespace
else else
{ {
size_t slicePitch; 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); auto sPtr = static_cast<const uint8_t*>(pSource);
@ -596,7 +598,9 @@ namespace
else else
{ {
size_t slicePitch; 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); 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)) 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 // 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)) if (!ReadFile(hFile.get(), image.GetPixels(), static_cast<DWORD>(image.GetPixelsSize()), &bytesRead, nullptr))
{ {
image.Release(); image.Release();
@ -1253,7 +1269,9 @@ HRESULT DirectX::SaveToTGAMemory(const Image& image, Blob& blob)
} }
else 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); 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; size_t rowPitch, slicePitch;
if (convFlags & CONV_FLAGS_888) if (convFlags & CONV_FLAGS_888)
{ {
rowPitch = image.width * 3; uint64_t pitch = uint64_t(image.width) * 3u;
slicePitch = image.height * rowPitch; 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 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) if (slicePitch < 65535)
@ -1375,6 +1406,9 @@ HRESULT DirectX::SaveToTGAFile(const Image& image, const wchar_t* szFile)
if (bytesWritten != sizeof(TGA_HEADER)) if (bytesWritten != sizeof(TGA_HEADER))
return E_FAIL; return E_FAIL;
if (rowPitch > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
// Write pixels // Write pixels
const uint8_t* pPixels = image.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 // based on DXGI format, width, and height
//------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------
_Use_decl_annotations_ _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) size_t& rowPitch, size_t& slicePitch, DWORD flags)
{ {
uint64_t pitch = 0;
uint64_t slice = 0;
switch (static_cast<int>(fmt)) switch (static_cast<int>(fmt))
{ {
case DXGI_FORMAT_BC1_TYPELESS: 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 nbw = width >> 2;
size_t nbh = height >> 2; size_t nbh = height >> 2;
rowPitch = std::max<size_t>(1, nbw * 8); pitch = std::max<uint64_t>(1u, uint64_t(nbw) * 8u);
slicePitch = std::max<size_t>(1, rowPitch * nbh); slice = std::max<uint64_t>(1u, pitch * uint64_t(nbh));
} }
else else
{ {
size_t nbw = std::max<size_t>(1, (width + 3) / 4); uint64_t nbw = std::max<uint64_t>(1u, (uint64_t(width) + 3u) / 4u);
size_t nbh = std::max<size_t>(1, (height + 3) / 4); uint64_t nbh = std::max<uint64_t>(1u, (uint64_t(height) + 3u) / 4u);
rowPitch = nbw * 8; pitch = nbw * 8u;
slicePitch = rowPitch * nbh; slice = pitch * nbh;
} }
} }
break; break;
@ -921,15 +924,15 @@ void DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height,
{ {
size_t nbw = width >> 2; size_t nbw = width >> 2;
size_t nbh = height >> 2; size_t nbh = height >> 2;
rowPitch = std::max<size_t>(1, nbw * 16); pitch = std::max<uint64_t>(1u, uint64_t(nbw) * 16u);
slicePitch = std::max<size_t>(1, rowPitch * nbh); slice = std::max<uint64_t>(1u, pitch * uint64_t(nbh));
} }
else else
{ {
size_t nbw = std::max<size_t>(1, (width + 3) / 4); uint64_t nbw = std::max<uint64_t>(1u, (uint64_t(width) + 3u) / 4u);
size_t nbh = std::max<size_t>(1, (height + 3) / 4); uint64_t nbh = std::max<uint64_t>(1u, (uint64_t(height) + 3u) / 4u);
rowPitch = nbw * 16; pitch = nbw * 16u;
slicePitch = rowPitch * nbh; slice = pitch * nbh;
} }
} }
break; 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_G8R8_G8B8_UNORM:
case DXGI_FORMAT_YUY2: case DXGI_FORMAT_YUY2:
assert(IsPacked(fmt)); assert(IsPacked(fmt));
rowPitch = ((width + 1) >> 1) * 4; pitch = ((uint64_t(width) + 1u) >> 1) * 4u;
slicePitch = rowPitch * height; slice = pitch * uint64_t(height);
break; break;
case DXGI_FORMAT_Y210: case DXGI_FORMAT_Y210:
case DXGI_FORMAT_Y216: case DXGI_FORMAT_Y216:
assert(IsPacked(fmt)); assert(IsPacked(fmt));
rowPitch = ((width + 1) >> 1) * 8; pitch = ((uint64_t(width) + 1u) >> 1) * 8u;
slicePitch = rowPitch * height; slice = pitch * uint64_t(height);
break; break;
case DXGI_FORMAT_NV12: case DXGI_FORMAT_NV12:
case DXGI_FORMAT_420_OPAQUE: case DXGI_FORMAT_420_OPAQUE:
assert(IsPlanar(fmt)); assert(IsPlanar(fmt));
rowPitch = ((width + 1) >> 1) * 2; pitch = ((uint64_t(width) + 1u) >> 1) * 2u;
slicePitch = rowPitch * (height + ((height + 1) >> 1)); slice = pitch * (uint64_t(height) + ((uint64_t(height) + 1u) >> 1));
break; break;
case DXGI_FORMAT_P010: 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_R16_UNORM_X8_TYPELESS:
case XBOX_DXGI_FORMAT_X16_TYPELESS_G8_UINT: case XBOX_DXGI_FORMAT_X16_TYPELESS_G8_UINT:
assert(IsPlanar(fmt)); assert(IsPlanar(fmt));
rowPitch = ((width + 1) >> 1) * 4; pitch = ((uint64_t(width) + 1u) >> 1) * 4u;
slicePitch = rowPitch * (height + ((height + 1) >> 1)); slice = pitch * (uint64_t(height) + ((uint64_t(height) + 1u) >> 1));
break; break;
case DXGI_FORMAT_NV11: case DXGI_FORMAT_NV11:
assert(IsPlanar(fmt)); assert(IsPlanar(fmt));
rowPitch = ((width + 3) >> 2) * 4; pitch = ((uint64_t(width) + 3u) >> 2) * 4u;
slicePitch = rowPitch * height * 2; slice = pitch * uint64_t(height) * 2u;
break; break;
case WIN10_DXGI_FORMAT_P208: case WIN10_DXGI_FORMAT_P208:
assert(IsPlanar(fmt)); assert(IsPlanar(fmt));
rowPitch = ((width + 1) >> 1) * 2; pitch = ((uint64_t(width) + 1u) >> 1) * 2u;
slicePitch = rowPitch * height * 2; slice = pitch * uint64_t(height) * 2u;
break; break;
case WIN10_DXGI_FORMAT_V208: case WIN10_DXGI_FORMAT_V208:
assert(IsPlanar(fmt)); assert(IsPlanar(fmt));
rowPitch = width; pitch = uint64_t(width);
slicePitch = rowPitch * (height + (((height + 1) >> 1) * 2)); slice = pitch * (uint64_t(height) + (((uint64_t(height) + 1u) >> 1) * 2u));
break; break;
case WIN10_DXGI_FORMAT_V408: case WIN10_DXGI_FORMAT_V408:
assert(IsPlanar(fmt)); assert(IsPlanar(fmt));
rowPitch = width; pitch = uint64_t(width);
slicePitch = rowPitch * (height + ((height >> 1) * 4)); slice = pitch * (uint64_t(height) + (uint64_t(height >> 1) * 4u));
break; break;
default: default:
assert(IsValid(fmt));
assert(!IsCompressed(fmt) && !IsPacked(fmt) && !IsPlanar(fmt)); assert(!IsCompressed(fmt) && !IsPacked(fmt) && !IsPlanar(fmt));
{ {
size_t bpp; size_t bpp;
if (flags & CP_FLAGS_24BPP) if (flags & CP_FLAGS_24BPP)
@ -1006,45 +1007,64 @@ void DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height,
else else
bpp = BitsPerPixel(fmt); 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_LEGACY_DWORD | CP_FLAGS_PARAGRAPH | CP_FLAGS_YMM | CP_FLAGS_ZMM | CP_FLAGS_PAGE4K))
{ {
if (flags & CP_FLAGS_PAGE4K) if (flags & CP_FLAGS_PAGE4K)
{ {
rowPitch = ((width * bpp + 32767) / 32768) * 4096; pitch = ((uint64_t(width) * bpp + 32767u) / 32768u) * 4096u;
slicePitch = rowPitch * height; slice = pitch * uint64_t(height);
} }
else if (flags & CP_FLAGS_ZMM) else if (flags & CP_FLAGS_ZMM)
{ {
rowPitch = ((width * bpp + 511) / 512) * 64; pitch = ((uint64_t(width) * bpp + 511u) / 512u) * 64u;
slicePitch = rowPitch * height; slice = pitch * uint64_t(height);
} }
else if (flags & CP_FLAGS_YMM) else if (flags & CP_FLAGS_YMM)
{ {
rowPitch = ((width * bpp + 255) / 256) * 32; pitch = ((uint64_t(width) * bpp + 255u) / 256u) * 32u;
slicePitch = rowPitch * height; slice = pitch * uint64_t(height);
} }
else if (flags & CP_FLAGS_PARAGRAPH) else if (flags & CP_FLAGS_PARAGRAPH)
{ {
rowPitch = ((width * bpp + 127) / 128) * 16; pitch = ((uint64_t(width) * bpp + 127u) / 128u) * 16u;
slicePitch = rowPitch * height; slice = pitch * uint64_t(height);
} }
else // DWORD alignment else // DWORD alignment
{ {
// Special computation for some incorrectly created DDS files based on // Special computation for some incorrectly created DDS files based on
// legacy DirectDraw assumptions about pitch alignment // legacy DirectDraw assumptions about pitch alignment
rowPitch = ((width * bpp + 31) / 32) * sizeof(uint32_t); pitch = ((uint64_t(width) * bpp + 31u) / 32u) * sizeof(uint32_t);
slicePitch = rowPitch * height; slice = pitch * uint64_t(height);
} }
} }
else else
{ {
// Default byte alignment // Default byte alignment
rowPitch = (width * bpp + 7) / 8; pitch = (uint64_t(width) * bpp + 7u) / 8u;
slicePitch = rowPitch * height; slice = pitch * uint64_t(height);
} }
} }
break; 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 // Get surface information for a particular format
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
void GetSurfaceInfo( HRESULT GetSurfaceInfo(
_In_ size_t width, _In_ size_t width,
_In_ size_t height, _In_ size_t height,
_In_ DXGI_FORMAT fmt, _In_ DXGI_FORMAT fmt,
_Out_opt_ size_t* outNumBytes, _Out_opt_ size_t* outNumBytes,
_Out_opt_ size_t* outRowBytes, _Out_opt_ size_t* outRowBytes,
_Out_opt_ size_t* outNumRows ) _Out_opt_ size_t* outNumRows)
{ {
size_t numBytes = 0; uint64_t numBytes = 0;
size_t rowBytes = 0; uint64_t rowBytes = 0;
size_t numRows = 0; uint64_t numRows = 0;
bool bc = false; bool bc = false;
bool packed = false; bool packed = false;
@ -458,7 +458,7 @@ namespace
case DXGI_FORMAT_BC4_TYPELESS: case DXGI_FORMAT_BC4_TYPELESS:
case DXGI_FORMAT_BC4_UNORM: case DXGI_FORMAT_BC4_UNORM:
case DXGI_FORMAT_BC4_SNORM: case DXGI_FORMAT_BC4_SNORM:
bc=true; bc = true;
bpe = 8; bpe = 8;
break; break;
@ -505,19 +505,22 @@ namespace
planar = true; planar = true;
bpe = 4; bpe = 4;
break; break;
default:
break;
} }
if (bc) if (bc)
{ {
size_t numBlocksWide = 0; uint64_t numBlocksWide = 0;
if (width > 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) 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; rowBytes = numBlocksWide * bpe;
numRows = numBlocksHigh; numRows = numBlocksHigh;
@ -525,42 +528,55 @@ namespace
} }
else if (packed) else if (packed)
{ {
rowBytes = ( ( width + 1 ) >> 1 ) * bpe; rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;
numRows = height; numRows = uint64_t(height);
numBytes = rowBytes * height; numBytes = rowBytes * height;
} }
else if ( fmt == DXGI_FORMAT_NV11 ) else if (fmt == DXGI_FORMAT_NV11)
{ {
rowBytes = ( ( width + 3 ) >> 2 ) * 4; rowBytes = ((uint64_t(width) + 3u) >> 2) * 4u;
numRows = height * 2; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data numRows = uint64_t(height) * 2u; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data
numBytes = rowBytes * numRows; numBytes = rowBytes * numRows;
} }
else if (planar) else if (planar)
{ {
rowBytes = ( ( width + 1 ) >> 1 ) * bpe; rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;
numBytes = ( rowBytes * height ) + ( ( rowBytes * height + 1 ) >> 1 ); numBytes = (rowBytes * uint64_t(height)) + ((rowBytes * uint64_t(height) + 1u) >> 1);
numRows = height + ( ( height + 1 ) >> 1 ); numRows = height + ((uint64_t(height) + 1u) >> 1);
} }
else else
{ {
size_t bpp = BitsPerPixel( fmt ); size_t bpp = BitsPerPixel(fmt);
rowBytes = ( width * bpp + 7 ) / 8; // round up to nearest byte if (!bpp)
numRows = height; return E_INVALIDARG;
rowBytes = (uint64_t(width) * bpp + 7u) / 8u; // round up to nearest byte
numRows = uint64_t(height);
numBytes = rowBytes * 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) if (outNumBytes)
{ {
*outNumBytes = numBytes; *outNumBytes = static_cast<size_t>(numBytes);
} }
if (outRowBytes) if (outRowBytes)
{ {
*outRowBytes = rowBytes; *outRowBytes = static_cast<size_t>(rowBytes);
} }
if (outNumRows) 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; 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) if (rowPitch > UINT32_MAX || slicePitch > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);

View File

@ -325,6 +325,7 @@ namespace
case DXGI_FORMAT_P010: case DXGI_FORMAT_P010:
case DXGI_FORMAT_P016: case DXGI_FORMAT_P016:
case DXGI_FORMAT_V408:
return 24; return 24;
case DXGI_FORMAT_R8G8_TYPELESS: case DXGI_FORMAT_R8G8_TYPELESS:
@ -343,6 +344,8 @@ namespace
case DXGI_FORMAT_B5G5R5A1_UNORM: case DXGI_FORMAT_B5G5R5A1_UNORM:
case DXGI_FORMAT_A8P8: case DXGI_FORMAT_A8P8:
case DXGI_FORMAT_B4G4R4A4_UNORM: case DXGI_FORMAT_B4G4R4A4_UNORM:
case DXGI_FORMAT_P208:
case DXGI_FORMAT_V208:
return 16; return 16;
case DXGI_FORMAT_NV12: case DXGI_FORMAT_NV12:
@ -434,17 +437,17 @@ namespace
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
// Get surface information for a particular format // Get surface information for a particular format
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
void GetSurfaceInfo( HRESULT GetSurfaceInfo(
_In_ size_t width, _In_ size_t width,
_In_ size_t height, _In_ size_t height,
_In_ DXGI_FORMAT fmt, _In_ DXGI_FORMAT fmt,
_Out_opt_ size_t* outNumBytes, _Out_opt_ size_t* outNumBytes,
_Out_opt_ size_t* outRowBytes, _Out_opt_ size_t* outRowBytes,
_Out_opt_ size_t* outNumRows ) _Out_opt_ size_t* outNumRows)
{ {
size_t numBytes = 0; uint64_t numBytes = 0;
size_t rowBytes = 0; uint64_t rowBytes = 0;
size_t numRows = 0; uint64_t numRows = 0;
bool bc = false; bool bc = false;
bool packed = false; bool packed = false;
@ -458,7 +461,7 @@ namespace
case DXGI_FORMAT_BC4_TYPELESS: case DXGI_FORMAT_BC4_TYPELESS:
case DXGI_FORMAT_BC4_UNORM: case DXGI_FORMAT_BC4_UNORM:
case DXGI_FORMAT_BC4_SNORM: case DXGI_FORMAT_BC4_SNORM:
bc=true; bc = true;
bpe = 8; bpe = 8;
break; break;
@ -496,6 +499,7 @@ namespace
case DXGI_FORMAT_NV12: case DXGI_FORMAT_NV12:
case DXGI_FORMAT_420_OPAQUE: case DXGI_FORMAT_420_OPAQUE:
case DXGI_FORMAT_P208:
planar = true; planar = true;
bpe = 2; bpe = 2;
break; break;
@ -505,19 +509,22 @@ namespace
planar = true; planar = true;
bpe = 4; bpe = 4;
break; break;
default:
break;
} }
if (bc) if (bc)
{ {
size_t numBlocksWide = 0; uint64_t numBlocksWide = 0;
if (width > 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) 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; rowBytes = numBlocksWide * bpe;
numRows = numBlocksHigh; numRows = numBlocksHigh;
@ -525,42 +532,55 @@ namespace
} }
else if (packed) else if (packed)
{ {
rowBytes = ( ( width + 1 ) >> 1 ) * bpe; rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;
numRows = height; numRows = uint64_t(height);
numBytes = rowBytes * height; numBytes = rowBytes * height;
} }
else if ( fmt == DXGI_FORMAT_NV11 ) else if (fmt == DXGI_FORMAT_NV11)
{ {
rowBytes = ( ( width + 3 ) >> 2 ) * 4; rowBytes = ((uint64_t(width) + 3u) >> 2) * 4u;
numRows = height * 2; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data numRows = uint64_t(height) * 2u; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data
numBytes = rowBytes * numRows; numBytes = rowBytes * numRows;
} }
else if (planar) else if (planar)
{ {
rowBytes = ( ( width + 1 ) >> 1 ) * bpe; rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;
numBytes = ( rowBytes * height ) + ( ( rowBytes * height + 1 ) >> 1 ); numBytes = (rowBytes * uint64_t(height)) + ((rowBytes * uint64_t(height) + 1u) >> 1);
numRows = height + ( ( height + 1 ) >> 1 ); numRows = height + ((uint64_t(height) + 1u) >> 1);
} }
else else
{ {
size_t bpp = BitsPerPixel( fmt ); size_t bpp = BitsPerPixel(fmt);
rowBytes = ( width * bpp + 7 ) / 8; // round up to nearest byte if (!bpp)
numRows = height; return E_INVALIDARG;
rowBytes = (uint64_t(width) * bpp + 7u) / 8u; // round up to nearest byte
numRows = uint64_t(height);
numBytes = rowBytes * 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) if (outNumBytes)
{ {
*outNumBytes = numBytes; *outNumBytes = static_cast<size_t>(numBytes);
} }
if (outRowBytes) if (outRowBytes)
{ {
*outRowBytes = rowBytes; *outRowBytes = static_cast<size_t>(rowBytes);
} }
if (outNumRows) 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; 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) if (rowPitch > UINT32_MAX || slicePitch > UINT32_MAX)
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);