Workaround when using WIC for F32 images that exceed 32-bits (#112)
This commit is contained in:
parent
9b61fa93bd
commit
ba0280c500
@ -2627,6 +2627,97 @@ HRESULT DirectX::_ConvertFromR32G32B32A32(
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Convert DXGI image to/from GUID_WICPixelFormat64bppRGBAHalf (no range conversions)
|
||||
//-------------------------------------------------------------------------------------
|
||||
_Use_decl_annotations_
|
||||
HRESULT DirectX::_ConvertToR16G16B16A16(const Image& srcImage, ScratchImage& image)
|
||||
{
|
||||
if (!srcImage.pixels)
|
||||
return E_POINTER;
|
||||
|
||||
HRESULT hr = image.Initialize2D(DXGI_FORMAT_R16G16B16A16_FLOAT, srcImage.width, srcImage.height, 1, 1);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
ScopedAlignedArrayXMVECTOR scanline(static_cast<XMVECTOR*>(_aligned_malloc((sizeof(XMVECTOR) * srcImage.width), 16)));
|
||||
if (!scanline)
|
||||
{
|
||||
image.Release();
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
const Image *img = image.GetImage(0, 0, 0);
|
||||
if (!img)
|
||||
{
|
||||
image.Release();
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
uint8_t* pDest = img->pixels;
|
||||
if (!pDest)
|
||||
{
|
||||
image.Release();
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
const uint8_t *pSrc = srcImage.pixels;
|
||||
for (size_t h = 0; h < srcImage.height; ++h)
|
||||
{
|
||||
if (!_LoadScanline(scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format))
|
||||
{
|
||||
image.Release();
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
XMConvertFloatToHalfStream(
|
||||
reinterpret_cast<HALF*>(pDest), sizeof(HALF),
|
||||
reinterpret_cast<float*>(scanline.get()), sizeof(float),
|
||||
srcImage.width * 4);
|
||||
|
||||
pSrc += srcImage.rowPitch;
|
||||
pDest += img->rowPitch;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT DirectX::_ConvertFromR16G16B16A16(const Image& srcImage, const Image& destImage)
|
||||
{
|
||||
assert(srcImage.format == DXGI_FORMAT_R16G16B16A16_FLOAT);
|
||||
|
||||
if (!srcImage.pixels || !destImage.pixels)
|
||||
return E_POINTER;
|
||||
|
||||
if (srcImage.width != destImage.width || srcImage.height != destImage.height)
|
||||
return E_FAIL;
|
||||
|
||||
ScopedAlignedArrayXMVECTOR scanline(static_cast<XMVECTOR*>(_aligned_malloc((sizeof(XMVECTOR) * srcImage.width), 16)));
|
||||
if (!scanline)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
const uint8_t *pSrc = srcImage.pixels;
|
||||
uint8_t* pDest = destImage.pixels;
|
||||
|
||||
for (size_t h = 0; h < srcImage.height; ++h)
|
||||
{
|
||||
XMConvertHalfToFloatStream(
|
||||
reinterpret_cast<float*>(scanline.get()), sizeof(float),
|
||||
reinterpret_cast<const HALF*>(pSrc), sizeof(HALF),
|
||||
srcImage.width * 4);
|
||||
|
||||
if (!_StoreScanline(pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width))
|
||||
return E_FAIL;
|
||||
|
||||
pSrc += srcImage.rowPitch;
|
||||
pDest += destImage.rowPitch;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Convert from Linear RGB to sRGB
|
||||
//
|
||||
|
@ -84,7 +84,52 @@ namespace
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Do conversion, flip/rotate using WIC, conversion cycle
|
||||
//
|
||||
// For large images we have to use F16 instead of F32 to avoid exceeding the 32-bit
|
||||
// memory limitations of WIC.
|
||||
//-------------------------------------------------------------------------------------
|
||||
HRESULT PerformFlipRotateViaF16(
|
||||
const Image& srcImage,
|
||||
DWORD flags,
|
||||
const Image& destImage)
|
||||
{
|
||||
if (!srcImage.pixels || !destImage.pixels)
|
||||
return E_POINTER;
|
||||
|
||||
assert(srcImage.format != DXGI_FORMAT_R16G16B16A16_FLOAT);
|
||||
assert(srcImage.format == destImage.format);
|
||||
|
||||
ScratchImage temp;
|
||||
HRESULT hr = _ConvertToR16G16B16A16(srcImage, temp);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
const Image *tsrc = temp.GetImage(0, 0, 0);
|
||||
if (!tsrc)
|
||||
return E_POINTER;
|
||||
|
||||
ScratchImage rtemp;
|
||||
hr = rtemp.Initialize2D(DXGI_FORMAT_R16G16B16A16_FLOAT, destImage.width, destImage.height, 1, 1);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
const Image *tdest = rtemp.GetImage(0, 0, 0);
|
||||
if (!tdest)
|
||||
return E_POINTER;
|
||||
|
||||
hr = PerformFlipRotateUsingWIC(*tsrc, flags, GUID_WICPixelFormat64bppRGBAHalf, *tdest);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
temp.Release();
|
||||
|
||||
hr = _ConvertFromR16G16B16A16(*tdest, destImage);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT PerformFlipRotateViaF32(
|
||||
const Image& srcImage,
|
||||
DWORD flags,
|
||||
@ -206,7 +251,16 @@ HRESULT DirectX::FlipRotate(
|
||||
else
|
||||
{
|
||||
// Case 2: Source format is not supported by WIC, so we have to convert, flip/rotate, and convert back
|
||||
hr = PerformFlipRotateViaF32(srcImage, flags, *rimage);
|
||||
uint64_t expandedSize = uint64_t(srcImage.width) * uint64_t(srcImage.height) * sizeof(float) * 4;
|
||||
if (expandedSize > UINT32_MAX)
|
||||
{
|
||||
// Image is too large for float32, so have to use float16 instead
|
||||
hr = PerformFlipRotateViaF16(srcImage, flags, *rimage);
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = PerformFlipRotateViaF32(srcImage, flags, *rimage);
|
||||
}
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
@ -329,7 +383,16 @@ HRESULT DirectX::FlipRotate(
|
||||
else
|
||||
{
|
||||
// Case 2: Source format is not supported by WIC, so we have to convert, flip/rotate, and convert back
|
||||
hr = PerformFlipRotateViaF32(src, flags, dst);
|
||||
uint64_t expandedSize = uint64_t(src.width) * uint64_t(src.height) * sizeof(float) * 4;
|
||||
if (expandedSize > UINT32_MAX)
|
||||
{
|
||||
// Image is too large for float32, so have to use float16 instead
|
||||
hr = PerformFlipRotateViaF16(src, flags, dst);
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = PerformFlipRotateViaF32(src, flags, dst);
|
||||
}
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
|
@ -2564,7 +2564,26 @@ HRESULT DirectX::GenerateMipMaps(
|
||||
|
||||
static_assert(TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK");
|
||||
|
||||
if (UseWICFiltering(baseImage.format, filter))
|
||||
bool usewic = UseWICFiltering(baseImage.format, filter);
|
||||
|
||||
WICPixelFormatGUID pfGUID = {};
|
||||
bool wicpf = (usewic) ? _DXGIToWIC(baseImage.format, pfGUID, true) : false;
|
||||
|
||||
if (usewic && !wicpf)
|
||||
{
|
||||
// Check to see if the source and/or result size is too big for WIC
|
||||
uint64_t expandedSize = uint64_t(std::max<size_t>(1, baseImage.width >> 1)) * uint64_t(std::max<size_t>(1, baseImage.height >> 1)) * sizeof(float) * 4;
|
||||
uint64_t expandedSize2 = uint64_t(baseImage.width) * uint64_t(baseImage.height) * sizeof(float) * 4;
|
||||
if (expandedSize > UINT32_MAX || expandedSize2 > UINT32_MAX)
|
||||
{
|
||||
if (filter & TEX_FILTER_FORCE_WIC)
|
||||
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
|
||||
|
||||
usewic = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (usewic)
|
||||
{
|
||||
//--- Use WIC filtering to generate mipmaps -----------------------------------
|
||||
switch (filter & TEX_FILTER_MASK)
|
||||
@ -2577,8 +2596,7 @@ HRESULT DirectX::GenerateMipMaps(
|
||||
{
|
||||
static_assert(TEX_FILTER_FANT == TEX_FILTER_BOX, "TEX_FILTER_ flag alias mismatch");
|
||||
|
||||
WICPixelFormatGUID pfGUID;
|
||||
if (_DXGIToWIC(baseImage.format, pfGUID, true))
|
||||
if (wicpf)
|
||||
{
|
||||
// Case 1: Base image format is supported by Windows Imaging Component
|
||||
hr = (baseImage.height > 1 || !allow1D)
|
||||
@ -2754,9 +2772,31 @@ HRESULT DirectX::GenerateMipMaps(
|
||||
|
||||
HRESULT hr = E_UNEXPECTED;
|
||||
|
||||
if (baseImages.empty())
|
||||
return hr;
|
||||
|
||||
static_assert(TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK");
|
||||
|
||||
if (!metadata.IsPMAlpha() && UseWICFiltering(metadata.format, filter))
|
||||
bool usewic = !metadata.IsPMAlpha() && UseWICFiltering(metadata.format, filter);
|
||||
|
||||
WICPixelFormatGUID pfGUID = {};
|
||||
bool wicpf = (usewic) ? _DXGIToWIC(metadata.format, pfGUID, true) : false;
|
||||
|
||||
if (usewic && !wicpf)
|
||||
{
|
||||
// Check to see if the source and/or result size is too big for WIC
|
||||
uint64_t expandedSize = uint64_t(std::max<size_t>(1, metadata.width >> 1)) * uint64_t(std::max<size_t>(1, metadata.height >> 1)) * sizeof(float) * 4;
|
||||
uint64_t expandedSize2 = uint64_t(metadata.width) * uint64_t(metadata.height) * sizeof(float) * 4;
|
||||
if (expandedSize > UINT32_MAX || expandedSize2 > UINT32_MAX)
|
||||
{
|
||||
if (filter & TEX_FILTER_FORCE_WIC)
|
||||
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
|
||||
|
||||
usewic = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (usewic)
|
||||
{
|
||||
//--- Use WIC filtering to generate mipmaps -----------------------------------
|
||||
switch (filter & TEX_FILTER_MASK)
|
||||
@ -2769,8 +2809,7 @@ HRESULT DirectX::GenerateMipMaps(
|
||||
{
|
||||
static_assert(TEX_FILTER_FANT == TEX_FILTER_BOX, "TEX_FILTER_ flag alias mismatch");
|
||||
|
||||
WICPixelFormatGUID pfGUID;
|
||||
if (_DXGIToWIC(metadata.format, pfGUID, true))
|
||||
if (wicpf)
|
||||
{
|
||||
// Case 1: Base image format is supported by Windows Imaging Component
|
||||
TexMetadata mdata2 = metadata;
|
||||
|
@ -272,6 +272,10 @@ namespace DirectX
|
||||
_In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,
|
||||
_In_ DXGI_FORMAT format, _Out_ ScratchImage& result);
|
||||
|
||||
HRESULT __cdecl _ConvertToR16G16B16A16(_In_ const Image& srcImage, _Inout_ ScratchImage& image);
|
||||
|
||||
HRESULT __cdecl _ConvertFromR16G16B16A16(_In_ const Image& srcImage, _In_ const Image& destImage);
|
||||
|
||||
void __cdecl _ConvertScanline(
|
||||
_Inout_updates_all_(count) XMVECTOR* pBuffer, _In_ size_t count,
|
||||
_In_ DXGI_FORMAT outFormat, _In_ DXGI_FORMAT inFormat, _In_ DWORD flags);
|
||||
|
@ -862,6 +862,25 @@ HRESULT DirectX::Resize(
|
||||
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
bool usewic = UseWICFiltering(srcImage.format, filter);
|
||||
|
||||
WICPixelFormatGUID pfGUID = {};
|
||||
bool wicpf = (usewic) ? _DXGIToWIC(srcImage.format, pfGUID, true) : false;
|
||||
|
||||
if (usewic && !wicpf)
|
||||
{
|
||||
// Check to see if the source and/or result size is too big for WIC
|
||||
uint64_t expandedSize = uint64_t(width) * uint64_t(height) * sizeof(float) * 4;
|
||||
uint64_t expandedSize2 = uint64_t(srcImage.width) * uint64_t(srcImage.height) * sizeof(float) * 4;
|
||||
if (expandedSize > UINT32_MAX || expandedSize2 > UINT32_MAX)
|
||||
{
|
||||
if (filter & TEX_FILTER_FORCE_WIC)
|
||||
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
|
||||
|
||||
usewic = false;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr = image.Initialize2D(srcImage.format, width, height, 1, 1);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
@ -870,10 +889,9 @@ HRESULT DirectX::Resize(
|
||||
if (!rimage)
|
||||
return E_POINTER;
|
||||
|
||||
if (UseWICFiltering(srcImage.format, filter))
|
||||
if (usewic)
|
||||
{
|
||||
WICPixelFormatGUID pfGUID;
|
||||
if (_DXGIToWIC(srcImage.format, pfGUID, true))
|
||||
if (wicpf)
|
||||
{
|
||||
// Case 1: Source format is supported by Windows Imaging Component
|
||||
hr = PerformResizeUsingWIC(srcImage, filter, pfGUID, *rimage);
|
||||
@ -886,6 +904,7 @@ HRESULT DirectX::Resize(
|
||||
}
|
||||
else
|
||||
{
|
||||
// Case 3: not using WIC resizing
|
||||
hr = PerformResizeUsingCustomFilters(srcImage, filter, *rimage);
|
||||
}
|
||||
|
||||
@ -931,6 +950,20 @@ HRESULT DirectX::Resize(
|
||||
WICPixelFormatGUID pfGUID = {};
|
||||
bool wicpf = (usewic) ? _DXGIToWIC(metadata.format, pfGUID, true) : false;
|
||||
|
||||
if (usewic && !wicpf)
|
||||
{
|
||||
// Check to see if the source and/or result size is too big for WIC
|
||||
uint64_t expandedSize = uint64_t(width) * uint64_t(height) * sizeof(float) * 4;
|
||||
uint64_t expandedSize2 = uint64_t(metadata.width) * uint64_t(metadata.height) * sizeof(float) * 4;
|
||||
if (expandedSize > UINT32_MAX || expandedSize2 > UINT32_MAX)
|
||||
{
|
||||
if (filter & TEX_FILTER_FORCE_WIC)
|
||||
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
|
||||
|
||||
usewic = false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (metadata.dimension)
|
||||
{
|
||||
case TEX_DIMENSION_TEXTURE1D:
|
||||
|
@ -80,6 +80,7 @@ enum OPTIONS
|
||||
OPT_USE_DX10,
|
||||
OPT_NOLOGO,
|
||||
OPT_SEPALPHA,
|
||||
OPT_NO_WIC,
|
||||
OPT_DEMUL_ALPHA,
|
||||
OPT_TA_WRAP,
|
||||
OPT_TA_MIRROR,
|
||||
@ -136,6 +137,7 @@ const SValue g_pOptions [] =
|
||||
{ L"dx10", OPT_USE_DX10 },
|
||||
{ L"nologo", OPT_NOLOGO },
|
||||
{ L"sepalpha", OPT_SEPALPHA },
|
||||
{ L"nowic", OPT_NO_WIC },
|
||||
{ L"alpha", OPT_DEMUL_ALPHA },
|
||||
{ L"wrap", OPT_TA_WRAP },
|
||||
{ L"mirror", OPT_TA_MIRROR },
|
||||
@ -519,6 +521,7 @@ namespace
|
||||
wprintf(L" -o <filename> output filename\n");
|
||||
wprintf(L" -y overwrite existing output file (if any)\n");
|
||||
wprintf(L" -sepalpha resize alpha channel separately from color channels\n");
|
||||
wprintf(L" -nowic Force non-WIC filtering\n");
|
||||
wprintf(L" -wrap, -mirror texture addressing mode (wrap, mirror, or clamp)\n");
|
||||
wprintf(L" -alpha convert premultiplied alpha to straight alpha\n");
|
||||
wprintf(L" -dx10 Force use of 'DX10' extended header\n");
|
||||
@ -1067,6 +1070,10 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
|
||||
dwFilterOpts |= TEX_FILTER_SEPARATE_ALPHA;
|
||||
break;
|
||||
|
||||
case OPT_NO_WIC:
|
||||
dwFilterOpts |= TEX_FILTER_FORCE_NON_WIC;
|
||||
break;
|
||||
|
||||
case OPT_OUTPUTFILE:
|
||||
{
|
||||
wcscpy_s(szOutputFile, MAX_PATH, pValue);
|
||||
|
@ -75,6 +75,7 @@ enum OPTIONS
|
||||
OPT_NOLOGO,
|
||||
OPT_TIMING,
|
||||
OPT_SEPALPHA,
|
||||
OPT_NO_WIC,
|
||||
OPT_TYPELESS_UNORM,
|
||||
OPT_TYPELESS_FLOAT,
|
||||
OPT_PREMUL_ALPHA,
|
||||
@ -159,6 +160,7 @@ const SValue g_pOptions[] =
|
||||
{ L"nologo", OPT_NOLOGO },
|
||||
{ L"timing", OPT_TIMING },
|
||||
{ L"sepalpha", OPT_SEPALPHA },
|
||||
{ L"nowic", OPT_NO_WIC },
|
||||
{ L"tu", OPT_TYPELESS_UNORM },
|
||||
{ L"tf", OPT_TYPELESS_FLOAT },
|
||||
{ L"pmalpha", OPT_PREMUL_ALPHA },
|
||||
@ -707,6 +709,7 @@ namespace
|
||||
wprintf(L" -vflip vertical flip of source image\n");
|
||||
wprintf(L" -sepalpha resize/generate mips alpha channel separately\n");
|
||||
wprintf(L" from color channels\n");
|
||||
wprintf(L" -nowic Force non-WIC filtering\n");
|
||||
wprintf(L" -wrap, -mirror texture addressing mode (wrap, mirror, or clamp)\n");
|
||||
wprintf(L" -pmalpha convert final texture to use premultiplied alpha\n");
|
||||
wprintf(L" -alpha convert premultiplied alpha to straight alpha\n");
|
||||
@ -743,7 +746,7 @@ namespace
|
||||
L" (defaults to 1.0)\n");
|
||||
wprintf(L" -c <hex-RGB> colorkey (a.k.a. chromakey) transparency\n");
|
||||
wprintf(L" -rotatecolor <rot> rotates color primaries and/or applies a curve\n");
|
||||
wprintf(L" -nits <value> paper-white value in nits to use for HDR10 (defaults to 200.0)\n");
|
||||
wprintf(L" -nits <value> paper-white value in nits to use for HDR10 (def: 200.0)\n");
|
||||
wprintf(L" -tonemap Apply a tonemap operator based on maximum luminance\n");
|
||||
wprintf(L" -x2bias Enable *2 - 1 conversion cases for unorm/pos-only-float\n");
|
||||
wprintf(L" -flist <filename> use text file with a list of input files (one per line)\n");
|
||||
@ -1276,6 +1279,10 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
|
||||
dwFilterOpts |= TEX_FILTER_SEPARATE_ALPHA;
|
||||
break;
|
||||
|
||||
case OPT_NO_WIC:
|
||||
dwFilterOpts |= TEX_FILTER_FORCE_NON_WIC;
|
||||
break;
|
||||
|
||||
case OPT_PREFIX:
|
||||
wcscpy_s(szPrefix, MAX_PATH, pValue);
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user