diff --git a/DirectXTex/DirectXTex.h b/DirectXTex/DirectXTex.h index 6d943327..c9afdbda 100644 --- a/DirectXTex/DirectXTex.h +++ b/DirectXTex/DirectXTex.h @@ -572,11 +572,15 @@ namespace DirectX TEX_FILTER_FLOAT_X2BIAS = 0x200, // Enable *2 - 1 conversion cases for unorm<->float and positive-only float formats + TEX_FILTER_FLOAT16_SATURATE_TO_INF = 0x400, + TEX_FILTER_FLOAT16_KEEP_NANS = 0x800, + // Float to half16 conversion options + TEX_FILTER_RGB_COPY_RED = 0x1000, TEX_FILTER_RGB_COPY_GREEN = 0x2000, TEX_FILTER_RGB_COPY_BLUE = 0x4000, // When converting RGB to R, defaults to using grayscale. These flags indicate copying a specific channel instead - // When converting RGB to RG, defaults to copying RED | GREEN. These flags control which channels are selected instead. + // When converting RGB to RG, defaults to copying RED | GREEN. These flags control which channels are selected instead TEX_FILTER_DITHER = 0x10000, // Use ordered 4x4 dithering for any required conversions diff --git a/DirectXTex/DirectXTexConvert.cpp b/DirectXTex/DirectXTexConvert.cpp index 1625befe..a1515f55 100644 --- a/DirectXTex/DirectXTexConvert.cpp +++ b/DirectXTex/DirectXTexConvert.cpp @@ -1659,9 +1659,7 @@ bool DirectX::Internal::StoreScanline( for (size_t icount = 0; icount < (size - sizeof(XMHALF4) + 1); icount += sizeof(XMHALF4)) { if (sPtr >= ePtr) break; - XMVECTOR v = *sPtr++; - v = XMVectorClamp(v, g_HalfMin, g_HalfMax); - XMStoreHalf4(dPtr++, v); + XMStoreHalf4(dPtr++, *sPtr++); } return true; } @@ -1852,9 +1850,7 @@ bool DirectX::Internal::StoreScanline( for (size_t icount = 0; icount < (size - sizeof(HALF) + 1); icount += sizeof(HALF)) { if (sPtr >= ePtr) break; - float v = XMVectorGetX(*sPtr++); - v = std::max(std::min(v, 65504.f), -65504.f); - *(dPtr++) = XMConvertFloatToHalf(v); + *(dPtr++) = XMConvertFloatToHalf(XMVectorGetX(*sPtr++)); } return true; } @@ -3723,6 +3719,27 @@ void DirectX::Internal::ConvertScanline( } } } + + // Half-float sanitization + if (((out->flags & (CONVF_FLOAT | CONVF_DEPTH)) == CONVF_FLOAT) + && (out->datasize == 16) + && ((flags & (TEX_FILTER_FLOAT16_SATURATE_TO_INF | TEX_FILTER_FLOAT16_KEEP_NANS)) != (TEX_FILTER_FLOAT16_SATURATE_TO_INF | TEX_FILTER_FLOAT16_KEEP_NANS))) + { + const XMVECTOR zero = XMVectorZero(); + XMVECTOR* ptr = pBuffer; + for (size_t i = 0; i < count; ++i, ++ptr) + { + XMVECTOR v = *ptr; + + if (!(flags & TEX_FILTER_FLOAT16_SATURATE_TO_INF)) + v = XMVectorClamp(v, g_HalfMin, g_HalfMax); + + if (!(flags & TEX_FILTER_FLOAT16_KEEP_NANS)) + v = XMVectorSelect(v, zero, XMVectorIsNaN(v)); + + *ptr = v; + } + } } @@ -4441,6 +4458,12 @@ namespace return false; } + if (filter & (TEX_FILTER_FLOAT16_SATURATE_TO_INF | TEX_FILTER_FLOAT16_KEEP_NANS)) + { + // Float16 specials preservation not supported by WIC code paths + return false; + } + // Check for special cases #if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX) if (sformat == DXGI_FORMAT_R16G16B16A16_FLOAT