1
0
mirror of https://github.com/microsoft/DirectXTex synced 2024-11-22 04:20:07 +00:00

DirectXTex: sRGB correct filtering for mipmap generation

This commit is contained in:
walbourn_cp 2013-06-06 17:58:23 -07:00
parent 0853752b5d
commit a9c0c4320e
3 changed files with 245 additions and 61 deletions

View File

@ -1862,6 +1862,75 @@ static inline XMVECTOR _TableEncodeGamma22( FXMVECTOR v )
return XMLoadFloat4( (XMFLOAT4*)f ); return XMLoadFloat4( (XMFLOAT4*)f );
} }
_Use_decl_annotations_
bool _StoreScanlineLinear( LPVOID pDestination, size_t size, DXGI_FORMAT format,
XMVECTOR* pSource, size_t count, DWORD flags )
{
assert( pDestination && size > 0 );
assert( pSource && count > 0 && (((uintptr_t)pSource & 0xF) == 0) );
assert( IsValid(format) && !IsVideo(format) && !IsTypeless(format) && !IsCompressed(format) );
switch ( format )
{
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
flags |= TEX_FILTER_SRGB;
break;
case DXGI_FORMAT_R32G32B32A32_FLOAT:
case DXGI_FORMAT_R32G32B32_FLOAT:
case DXGI_FORMAT_R16G16B16A16_FLOAT:
case DXGI_FORMAT_R16G16B16A16_UNORM:
case DXGI_FORMAT_R32G32_FLOAT:
case DXGI_FORMAT_R10G10B10A2_UNORM:
case DXGI_FORMAT_R11G11B10_FLOAT:
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_R16G16_FLOAT:
case DXGI_FORMAT_R16G16_UNORM:
case DXGI_FORMAT_R32_FLOAT:
case DXGI_FORMAT_R8G8_UNORM:
case DXGI_FORMAT_R16_FLOAT:
case DXGI_FORMAT_R16_UNORM:
case DXGI_FORMAT_R8_UNORM:
case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
case DXGI_FORMAT_R8G8_B8G8_UNORM:
case DXGI_FORMAT_G8R8_G8B8_UNORM:
case DXGI_FORMAT_B5G6R5_UNORM:
case DXGI_FORMAT_B5G5R5A1_UNORM:
case DXGI_FORMAT_B8G8R8A8_UNORM:
case DXGI_FORMAT_B8G8R8X8_UNORM:
#ifdef DXGI_1_2_FORMATS
case DXGI_FORMAT_B4G4R4A4_UNORM:
#endif
break;
default:
// can't treat A8, XR, Depth, SNORM, UINT, or SINT as sRGB
flags &= ~TEX_FILTER_SRGB;
break;
}
// sRGB output processing (RGB -> sRGB)
if ( flags & TEX_FILTER_SRGB_OUT )
{
// To avoid the need for another temporary scanline buffer, we allow this function to overwrite the source buffer in-place
// Given the intended usage in the filtering routines, this is not a problem.
XMVECTOR* ptr = pSource;
for( size_t i=0; i < count; ++i )
{
// rgb = rgb^(1/2.2); a=a
XMVECTOR v = *ptr;
XMVECTOR v1 = _TableEncodeGamma22( v );
// Use table instead of XMVectorPow( v, [1/2.2f 1/2.2f 1/2.2f 1]).
// Note table lookup will also saturate the result
*ptr++ = XMVectorSelect( v, v1, g_XMSelect1110 );
}
}
return _StoreScanline( pDestination, size, format, pSource, count );
}
//------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------
// sRGB -> RGB // sRGB -> RGB
@ -1902,7 +1971,6 @@ static const uint32_t g_fDecodeGamma22[] =
0x3f795b20, 0x3f7a7651, 0x3f7b91a2, 0x3f7cad0e, 0x3f7dc896, 0x3f7ee43c, 0x3f800000, 0x3f800000 0x3f795b20, 0x3f7a7651, 0x3f7b91a2, 0x3f7cad0e, 0x3f7dc896, 0x3f7ee43c, 0x3f800000, 0x3f800000
}; };
#pragma prefast(suppress : 25000, "FXMVECTOR is 16 bytes") #pragma prefast(suppress : 25000, "FXMVECTOR is 16 bytes")
static inline XMVECTOR _TableDecodeGamma22( FXMVECTOR v ) static inline XMVECTOR _TableDecodeGamma22( FXMVECTOR v )
{ {
@ -1925,6 +1993,78 @@ static inline XMVECTOR _TableDecodeGamma22( FXMVECTOR v )
return XMLoadFloat4( (XMFLOAT4*)f ); return XMLoadFloat4( (XMFLOAT4*)f );
} }
_Use_decl_annotations_
bool _LoadScanlineLinear( XMVECTOR* pDestination, size_t count,
LPCVOID pSource, size_t size, DXGI_FORMAT format, DWORD flags )
{
assert( pDestination && count > 0 && (((uintptr_t)pDestination & 0xF) == 0) );
assert( pSource && size > 0 );
assert( IsValid(format) && !IsVideo(format) && !IsTypeless(format,false) && !IsCompressed(format) );
switch ( format )
{
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
flags |= TEX_FILTER_SRGB;
break;
case DXGI_FORMAT_R32G32B32A32_FLOAT:
case DXGI_FORMAT_R32G32B32_FLOAT:
case DXGI_FORMAT_R16G16B16A16_FLOAT:
case DXGI_FORMAT_R16G16B16A16_UNORM:
case DXGI_FORMAT_R32G32_FLOAT:
case DXGI_FORMAT_R10G10B10A2_UNORM:
case DXGI_FORMAT_R11G11B10_FLOAT:
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_R16G16_FLOAT:
case DXGI_FORMAT_R16G16_UNORM:
case DXGI_FORMAT_R32_FLOAT:
case DXGI_FORMAT_R8G8_UNORM:
case DXGI_FORMAT_R16_FLOAT:
case DXGI_FORMAT_R16_UNORM:
case DXGI_FORMAT_R8_UNORM:
case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
case DXGI_FORMAT_R8G8_B8G8_UNORM:
case DXGI_FORMAT_G8R8_G8B8_UNORM:
case DXGI_FORMAT_B5G6R5_UNORM:
case DXGI_FORMAT_B5G5R5A1_UNORM:
case DXGI_FORMAT_B8G8R8A8_UNORM:
case DXGI_FORMAT_B8G8R8X8_UNORM:
#ifdef DXGI_1_2_FORMATS
case DXGI_FORMAT_B4G4R4A4_UNORM:
#endif
break;
default:
// can't treat A8, XR, Depth, SNORM, UINT, or SINT as sRGB
flags &= ~TEX_FILTER_SRGB;
break;
}
if ( _LoadScanline( pDestination, count, pSource, size, format ) )
{
// sRGB input processing (sRGB -> RGB)
if ( flags & TEX_FILTER_SRGB_IN )
{
XMVECTOR* ptr = pDestination;
for( size_t i=0; i < count; ++i )
{
// rgb = rgb^(2.2); a=a
XMVECTOR v = *ptr;
// Use table instead of XMVectorPow( v, [2.2f 2.2f 2.2f 1]).
// Note table lookup will also saturate the result
XMVECTOR v1 = _TableDecodeGamma22( v );
*ptr++ = XMVectorSelect( v, v1, g_XMSelect1110 );
}
}
return true;
}
return false;
}
//------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------
// Convert scanline based on source/target formats // Convert scanline based on source/target formats
@ -2083,11 +2223,41 @@ void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, D
assert( _GetConvertFlags( outFormat ) == out->flags ); assert( _GetConvertFlags( outFormat ) == out->flags );
// Handle SRGB filtering modes // Handle SRGB filtering modes
if ( IsSRGB( inFormat ) ) switch ( inFormat )
{
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
case DXGI_FORMAT_BC1_UNORM_SRGB:
case DXGI_FORMAT_BC2_UNORM_SRGB:
case DXGI_FORMAT_BC3_UNORM_SRGB:
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
case DXGI_FORMAT_BC7_UNORM_SRGB:
flags |= TEX_FILTER_SRGB_IN; flags |= TEX_FILTER_SRGB_IN;
break;
if ( IsSRGB( outFormat ) ) case DXGI_FORMAT_A8_UNORM:
case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
flags &= ~TEX_FILTER_SRGB_IN;
break;
}
switch ( outFormat )
{
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
case DXGI_FORMAT_BC1_UNORM_SRGB:
case DXGI_FORMAT_BC2_UNORM_SRGB:
case DXGI_FORMAT_BC3_UNORM_SRGB:
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
case DXGI_FORMAT_BC7_UNORM_SRGB:
flags |= TEX_FILTER_SRGB_OUT; flags |= TEX_FILTER_SRGB_OUT;
break;
case DXGI_FORMAT_A8_UNORM:
case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
flags &= ~TEX_FILTER_SRGB_OUT;
break;
}
if ( (flags & (TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT)) == (TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT) ) if ( (flags & (TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT)) == (TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT) )
{ {
@ -2097,7 +2267,7 @@ void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, D
// sRGB input processing (sRGB -> RGB) // sRGB input processing (sRGB -> RGB)
if ( flags & TEX_FILTER_SRGB_IN ) if ( flags & TEX_FILTER_SRGB_IN )
{ {
if ( (in->flags & CONVF_FLOAT) || (in->flags & CONVF_UNORM) ) if ( !(in->flags & CONVF_DEPTH) && ( (in->flags & CONVF_FLOAT) || (in->flags & CONVF_UNORM) ) )
{ {
XMVECTOR* ptr = pBuffer; XMVECTOR* ptr = pBuffer;
for( size_t i=0; i < count; ++i ) for( size_t i=0; i < count; ++i )
@ -2302,7 +2472,7 @@ void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, D
// sRGB output processing (RGB -> sRGB) // sRGB output processing (RGB -> sRGB)
if ( flags & TEX_FILTER_SRGB_OUT ) if ( flags & TEX_FILTER_SRGB_OUT )
{ {
if ( (out->flags & CONVF_FLOAT) || (out->flags & CONVF_UNORM) ) if ( !(out->flags & CONVF_DEPTH) && ( (out->flags & CONVF_FLOAT) || (out->flags & CONVF_UNORM) ) )
{ {
XMVECTOR* ptr = pBuffer; XMVECTOR* ptr = pBuffer;
for( size_t i=0; i < count; ++i ) for( size_t i=0; i < count; ++i )

View File

@ -380,6 +380,12 @@ static bool _UseWICFiltering( _In_ DXGI_FORMAT format, _In_ DWORD filter )
return true; return true;
} }
if ( IsSRGB(format) || (filter & TEX_FILTER_SRGB) )
{
// Use non-WIC code paths for sRGB correct filtering
return false;
}
static_assert( TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK" ); static_assert( TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK" );
switch ( filter & TEX_FILTER_MASK ) switch ( filter & TEX_FILTER_MASK )
@ -680,7 +686,7 @@ static HRESULT _Generate2DMipsPointFilter( _In_ size_t levels, _In_ const Scratc
//--- 2D Box Filter --- //--- 2D Box Filter ---
static HRESULT _Generate2DMipsBoxFilter( _In_ size_t levels, _In_ const ScratchImage& mipChain, _In_ size_t item ) static HRESULT _Generate2DMipsBoxFilter( _In_ size_t levels, _In_ DWORD filter, _In_ const ScratchImage& mipChain, _In_ size_t item )
{ {
if ( !mipChain.GetImages() ) if ( !mipChain.GetImages() )
return E_INVALIDARG; return E_INVALIDARG;
@ -744,13 +750,13 @@ static HRESULT _Generate2DMipsBoxFilter( _In_ size_t levels, _In_ const ScratchI
for( size_t y = 0; y < nheight; ++y ) for( size_t y = 0; y < nheight; ++y )
{ {
if ( !_LoadScanline( urow0, width, pSrc, rowPitch, src->format ) ) if ( !_LoadScanlineLinear( urow0, width, pSrc, rowPitch, src->format, filter ) )
return E_FAIL; return E_FAIL;
pSrc += rowPitch; pSrc += rowPitch;
if ( urow0 != urow1 ) if ( urow0 != urow1 )
{ {
if ( !_LoadScanline( urow1, width, pSrc, rowPitch, src->format ) ) if ( !_LoadScanlineLinear( urow1, width, pSrc, rowPitch, src->format, filter ) )
return E_FAIL; return E_FAIL;
pSrc += rowPitch; pSrc += rowPitch;
} }
@ -762,7 +768,7 @@ static HRESULT _Generate2DMipsBoxFilter( _In_ size_t levels, _In_ const ScratchI
AVERAGE4( target[ x ], urow0[ x2 ], urow1[ x2 ], urow2[ x2 ], urow3[ x2 ] ); AVERAGE4( target[ x ], urow0[ x2 ], urow1[ x2 ], urow2[ x2 ], urow3[ x2 ] );
} }
if ( !_StoreScanline( pDest, dest->rowPitch, dest->format, target, nwidth ) ) if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) )
return E_FAIL; return E_FAIL;
pDest += dest->rowPitch; pDest += dest->rowPitch;
} }
@ -847,7 +853,7 @@ static HRESULT _Generate2DMipsLinearFilter( _In_ size_t levels, _In_ DWORD filte
{ {
u0 = toY.u0; u0 = toY.u0;
if ( !_LoadScanline( row0, width, pSrc + (rowPitch * u0), rowPitch, src->format ) ) if ( !_LoadScanlineLinear( row0, width, pSrc + (rowPitch * u0), rowPitch, src->format, filter ) )
return E_FAIL; return E_FAIL;
} }
else else
@ -863,7 +869,7 @@ static HRESULT _Generate2DMipsLinearFilter( _In_ size_t levels, _In_ DWORD filte
{ {
u1 = toY.u1; u1 = toY.u1;
if ( !_LoadScanline( row1, width, pSrc + (rowPitch * u1), rowPitch, src->format ) ) if ( !_LoadScanlineLinear( row1, width, pSrc + (rowPitch * u1), rowPitch, src->format, filter ) )
return E_FAIL; return E_FAIL;
} }
@ -874,7 +880,7 @@ static HRESULT _Generate2DMipsLinearFilter( _In_ size_t levels, _In_ DWORD filte
BILINEAR_INTERPOLATE( target[x], toX, toY, row0, row1 ); BILINEAR_INTERPOLATE( target[x], toX, toY, row0, row1 );
} }
if ( !_StoreScanline( pDest, dest->rowPitch, dest->format, target, nwidth ) ) if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) )
return E_FAIL; return E_FAIL;
pDest += dest->rowPitch; pDest += dest->rowPitch;
} }
@ -966,7 +972,7 @@ static HRESULT _Generate2DMipsCubicFilter( _In_ size_t levels, _In_ DWORD filter
{ {
u0 = toY.u0; u0 = toY.u0;
if ( !_LoadScanline( row0, width, pSrc + (rowPitch * u0), rowPitch, src->format ) ) if ( !_LoadScanlineLinear( row0, width, pSrc + (rowPitch * u0), rowPitch, src->format, filter ) )
return E_FAIL; return E_FAIL;
} }
else if ( toY.u0 == u1 ) else if ( toY.u0 == u1 )
@ -999,7 +1005,7 @@ static HRESULT _Generate2DMipsCubicFilter( _In_ size_t levels, _In_ DWORD filter
{ {
u1 = toY.u1; u1 = toY.u1;
if ( !_LoadScanline( row1, width, pSrc + (rowPitch * u1), rowPitch, src->format ) ) if ( !_LoadScanlineLinear( row1, width, pSrc + (rowPitch * u1), rowPitch, src->format, filter ) )
return E_FAIL; return E_FAIL;
} }
else if ( toY.u1 == u2 ) else if ( toY.u1 == u2 )
@ -1025,7 +1031,7 @@ static HRESULT _Generate2DMipsCubicFilter( _In_ size_t levels, _In_ DWORD filter
{ {
u2 = toY.u2; u2 = toY.u2;
if ( !_LoadScanline( row2, width, pSrc + (rowPitch * u2), rowPitch, src->format ) ) if ( !_LoadScanlineLinear( row2, width, pSrc + (rowPitch * u2), rowPitch, src->format, filter ) )
return E_FAIL; return E_FAIL;
} }
else else
@ -1042,7 +1048,7 @@ static HRESULT _Generate2DMipsCubicFilter( _In_ size_t levels, _In_ DWORD filter
{ {
u3 = toY.u3; u3 = toY.u3;
if ( !_LoadScanline( row3, width, pSrc + (rowPitch * u3), rowPitch, src->format ) ) if ( !_LoadScanlineLinear( row3, width, pSrc + (rowPitch * u3), rowPitch, src->format, filter ) )
return E_FAIL; return E_FAIL;
} }
@ -1060,7 +1066,7 @@ static HRESULT _Generate2DMipsCubicFilter( _In_ size_t levels, _In_ DWORD filter
CUBIC_INTERPOLATE( target[x], toY.x, C0, C1, C2, C3 ); CUBIC_INTERPOLATE( target[x], toY.x, C0, C1, C2, C3 );
} }
if ( !_StoreScanline( pDest, dest->rowPitch, dest->format, target, nwidth ) ) if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) )
return E_FAIL; return E_FAIL;
pDest += dest->rowPitch; pDest += dest->rowPitch;
} }
@ -1277,7 +1283,7 @@ static HRESULT _Generate3DMipsPointFilter( _In_ size_t depth, _In_ size_t levels
//--- 3D Box Filter --- //--- 3D Box Filter ---
static HRESULT _Generate3DMipsBoxFilter( _In_ size_t depth, _In_ size_t levels, _In_ const ScratchImage& mipChain ) static HRESULT _Generate3DMipsBoxFilter( _In_ size_t depth, _In_ size_t levels, _In_ DWORD filter, _In_ const ScratchImage& mipChain )
{ {
if ( !depth || !mipChain.GetImages() ) if ( !depth || !mipChain.GetImages() )
return E_INVALIDARG; return E_INVALIDARG;
@ -1362,24 +1368,24 @@ static HRESULT _Generate3DMipsBoxFilter( _In_ size_t depth, _In_ size_t levels,
for( size_t y = 0; y < nheight; ++y ) for( size_t y = 0; y < nheight; ++y )
{ {
if ( !_LoadScanline( urow0, width, pSrc1, aRowPitch, srca->format ) ) if ( !_LoadScanlineLinear( urow0, width, pSrc1, aRowPitch, srca->format, filter ) )
return E_FAIL; return E_FAIL;
pSrc1 += aRowPitch; pSrc1 += aRowPitch;
if ( urow0 != urow1 ) if ( urow0 != urow1 )
{ {
if ( !_LoadScanline( urow1, width, pSrc1, aRowPitch, srca->format ) ) if ( !_LoadScanlineLinear( urow1, width, pSrc1, aRowPitch, srca->format, filter ) )
return E_FAIL; return E_FAIL;
pSrc1 += aRowPitch; pSrc1 += aRowPitch;
} }
if ( !_LoadScanline( vrow0, width, pSrc2, bRowPitch, srcb->format ) ) if ( !_LoadScanlineLinear( vrow0, width, pSrc2, bRowPitch, srcb->format, filter ) )
return E_FAIL; return E_FAIL;
pSrc2 += bRowPitch; pSrc2 += bRowPitch;
if ( vrow0 != vrow1 ) if ( vrow0 != vrow1 )
{ {
if ( !_LoadScanline( vrow1, width, pSrc2, bRowPitch, srcb->format ) ) if ( !_LoadScanlineLinear( vrow1, width, pSrc2, bRowPitch, srcb->format, filter ) )
return E_FAIL; return E_FAIL;
pSrc2 += bRowPitch; pSrc2 += bRowPitch;
} }
@ -1392,7 +1398,7 @@ static HRESULT _Generate3DMipsBoxFilter( _In_ size_t depth, _In_ size_t levels,
vrow0[ x2 ], vrow1[ x2 ], vrow2[ x2 ], vrow3[ x2 ] ); vrow0[ x2 ], vrow1[ x2 ], vrow2[ x2 ], vrow3[ x2 ] );
} }
if ( !_StoreScanline( pDest, dest->rowPitch, dest->format, target, nwidth ) ) if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) )
return E_FAIL; return E_FAIL;
pDest += dest->rowPitch; pDest += dest->rowPitch;
} }
@ -1417,13 +1423,13 @@ static HRESULT _Generate3DMipsBoxFilter( _In_ size_t depth, _In_ size_t levels,
for( size_t y = 0; y < nheight; ++y ) for( size_t y = 0; y < nheight; ++y )
{ {
if ( !_LoadScanline( urow0, width, pSrc, rowPitch, src->format ) ) if ( !_LoadScanlineLinear( urow0, width, pSrc, rowPitch, src->format, filter ) )
return E_FAIL; return E_FAIL;
pSrc += rowPitch; pSrc += rowPitch;
if ( urow0 != urow1 ) if ( urow0 != urow1 )
{ {
if ( !_LoadScanline( urow1, width, pSrc, rowPitch, src->format ) ) if ( !_LoadScanlineLinear( urow1, width, pSrc, rowPitch, src->format, filter ) )
return E_FAIL; return E_FAIL;
pSrc += rowPitch; pSrc += rowPitch;
} }
@ -1435,7 +1441,7 @@ static HRESULT _Generate3DMipsBoxFilter( _In_ size_t depth, _In_ size_t levels,
AVERAGE4( target[ x ], urow0[ x2 ], urow1[ x2 ], urow2[ x2 ], urow3[ x2 ] ); AVERAGE4( target[ x ], urow0[ x2 ], urow1[ x2 ], urow2[ x2 ], urow3[ x2 ] );
} }
if ( !_StoreScanline( pDest, dest->rowPitch, dest->format, target, nwidth ) ) if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) )
return E_FAIL; return E_FAIL;
pDest += dest->rowPitch; pDest += dest->rowPitch;
} }
@ -1538,8 +1544,8 @@ static HRESULT _Generate3DMipsLinearFilter( _In_ size_t depth, _In_ size_t level
{ {
u0 = toY.u0; u0 = toY.u0;
if ( !_LoadScanline( urow0, width, srca->pixels + (srca->rowPitch * u0), srca->rowPitch, srca->format ) if ( !_LoadScanlineLinear( urow0, width, srca->pixels + (srca->rowPitch * u0), srca->rowPitch, srca->format, filter )
|| !_LoadScanline( vrow0, width, srcb->pixels + (srcb->rowPitch * u0), srcb->rowPitch, srcb->format ) ) || !_LoadScanlineLinear( vrow0, width, srcb->pixels + (srcb->rowPitch * u0), srcb->rowPitch, srcb->format, filter ) )
return E_FAIL; return E_FAIL;
} }
else else
@ -1556,8 +1562,8 @@ static HRESULT _Generate3DMipsLinearFilter( _In_ size_t depth, _In_ size_t level
{ {
u1 = toY.u1; u1 = toY.u1;
if ( !_LoadScanline( urow1, width, srca->pixels + (srca->rowPitch * u1), srca->rowPitch, srca->format ) if ( !_LoadScanlineLinear( urow1, width, srca->pixels + (srca->rowPitch * u1), srca->rowPitch, srca->format, filter )
|| !_LoadScanline( vrow1, width, srcb->pixels + (srcb->rowPitch * u1), srcb->rowPitch, srcb->format ) ) || !_LoadScanlineLinear( vrow1, width, srcb->pixels + (srcb->rowPitch * u1), srcb->rowPitch, srcb->format, filter ) )
return E_FAIL; return E_FAIL;
} }
@ -1568,7 +1574,7 @@ static HRESULT _Generate3DMipsLinearFilter( _In_ size_t depth, _In_ size_t level
TRILINEAR_INTERPOLATE( target[x], toX, toY, toZ, urow0, urow1, vrow0, vrow1 ); TRILINEAR_INTERPOLATE( target[x], toX, toY, toZ, urow0, urow1, vrow0, vrow1 );
} }
if ( !_StoreScanline( pDest, dest->rowPitch, dest->format, target, nwidth ) ) if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) )
return E_FAIL; return E_FAIL;
pDest += dest->rowPitch; pDest += dest->rowPitch;
} }
@ -1601,7 +1607,7 @@ static HRESULT _Generate3DMipsLinearFilter( _In_ size_t depth, _In_ size_t level
{ {
u0 = toY.u0; u0 = toY.u0;
if ( !_LoadScanline( urow0, width, pSrc + (rowPitch * u0), rowPitch, src->format ) ) if ( !_LoadScanlineLinear( urow0, width, pSrc + (rowPitch * u0), rowPitch, src->format, filter ) )
return E_FAIL; return E_FAIL;
} }
else else
@ -1617,7 +1623,7 @@ static HRESULT _Generate3DMipsLinearFilter( _In_ size_t depth, _In_ size_t level
{ {
u1 = toY.u1; u1 = toY.u1;
if ( !_LoadScanline( urow1, width, pSrc + (rowPitch * u1), rowPitch, src->format ) ) if ( !_LoadScanlineLinear( urow1, width, pSrc + (rowPitch * u1), rowPitch, src->format, filter ) )
return E_FAIL; return E_FAIL;
} }
@ -1628,7 +1634,7 @@ static HRESULT _Generate3DMipsLinearFilter( _In_ size_t depth, _In_ size_t level
BILINEAR_INTERPOLATE( target[x], toX, toY, urow0, urow1 ); BILINEAR_INTERPOLATE( target[x], toX, toY, urow0, urow1 );
} }
if ( !_StoreScanline( pDest, dest->rowPitch, dest->format, target, nwidth ) ) if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) )
return E_FAIL; return E_FAIL;
pDest += dest->rowPitch; pDest += dest->rowPitch;
} }
@ -1748,10 +1754,10 @@ static HRESULT _Generate3DMipsCubicFilter( _In_ size_t depth, _In_ size_t levels
{ {
u0 = toY.u0; u0 = toY.u0;
if ( !_LoadScanline( urow[0], width, srca->pixels + (srca->rowPitch * u0), srca->rowPitch, srca->format ) if ( !_LoadScanlineLinear( urow[0], width, srca->pixels + (srca->rowPitch * u0), srca->rowPitch, srca->format, filter )
|| !_LoadScanline( urow[1], width, srcb->pixels + (srcb->rowPitch * u0), srcb->rowPitch, srcb->format ) || !_LoadScanlineLinear( urow[1], width, srcb->pixels + (srcb->rowPitch * u0), srcb->rowPitch, srcb->format, filter )
|| !_LoadScanline( urow[2], width, srcc->pixels + (srcc->rowPitch * u0), srcc->rowPitch, srcc->format ) || !_LoadScanlineLinear( urow[2], width, srcc->pixels + (srcc->rowPitch * u0), srcc->rowPitch, srcc->format, filter )
|| !_LoadScanline( urow[3], width, srcd->pixels + (srcd->rowPitch * u0), srcd->rowPitch, srcd->format ) ) || !_LoadScanlineLinear( urow[3], width, srcd->pixels + (srcd->rowPitch * u0), srcd->rowPitch, srcd->format, filter ) )
return E_FAIL; return E_FAIL;
} }
else if ( toY.u0 == u1 ) else if ( toY.u0 == u1 )
@ -1793,10 +1799,10 @@ static HRESULT _Generate3DMipsCubicFilter( _In_ size_t depth, _In_ size_t levels
{ {
u1 = toY.u1; u1 = toY.u1;
if ( !_LoadScanline( vrow[0], width, srca->pixels + (srca->rowPitch * u1), srca->rowPitch, srca->format ) if ( !_LoadScanlineLinear( vrow[0], width, srca->pixels + (srca->rowPitch * u1), srca->rowPitch, srca->format, filter )
|| !_LoadScanline( vrow[1], width, srcb->pixels + (srcb->rowPitch * u1), srcb->rowPitch, srcb->format ) || !_LoadScanlineLinear( vrow[1], width, srcb->pixels + (srcb->rowPitch * u1), srcb->rowPitch, srcb->format, filter )
|| !_LoadScanline( vrow[2], width, srcc->pixels + (srcc->rowPitch * u1), srcc->rowPitch, srcc->format ) || !_LoadScanlineLinear( vrow[2], width, srcc->pixels + (srcc->rowPitch * u1), srcc->rowPitch, srcc->format, filter )
|| !_LoadScanline( vrow[3], width, srcd->pixels + (srcd->rowPitch * u1), srcd->rowPitch, srcd->format ) ) || !_LoadScanlineLinear( vrow[3], width, srcd->pixels + (srcd->rowPitch * u1), srcd->rowPitch, srcd->format, filter ) )
return E_FAIL; return E_FAIL;
} }
else if ( toY.u1 == u2 ) else if ( toY.u1 == u2 )
@ -1828,10 +1834,10 @@ static HRESULT _Generate3DMipsCubicFilter( _In_ size_t depth, _In_ size_t levels
{ {
u2 = toY.u2; u2 = toY.u2;
if ( !_LoadScanline( srow[0], width, srca->pixels + (srca->rowPitch * u2), srca->rowPitch, srca->format ) if ( !_LoadScanlineLinear( srow[0], width, srca->pixels + (srca->rowPitch * u2), srca->rowPitch, srca->format, filter )
|| !_LoadScanline( srow[1], width, srcb->pixels + (srcb->rowPitch * u2), srcb->rowPitch, srcb->format ) || !_LoadScanlineLinear( srow[1], width, srcb->pixels + (srcb->rowPitch * u2), srcb->rowPitch, srcb->format, filter )
|| !_LoadScanline( srow[2], width, srcc->pixels + (srcc->rowPitch * u2), srcc->rowPitch, srcc->format ) || !_LoadScanlineLinear( srow[2], width, srcc->pixels + (srcc->rowPitch * u2), srcc->rowPitch, srcc->format, filter )
|| !_LoadScanline( srow[3], width, srcd->pixels + (srcd->rowPitch * u2), srcd->rowPitch, srcd->format ) ) || !_LoadScanlineLinear( srow[3], width, srcd->pixels + (srcd->rowPitch * u2), srcd->rowPitch, srcd->format, filter ) )
return E_FAIL; return E_FAIL;
} }
else else
@ -1851,10 +1857,10 @@ static HRESULT _Generate3DMipsCubicFilter( _In_ size_t depth, _In_ size_t levels
{ {
u3 = toY.u3; u3 = toY.u3;
if ( !_LoadScanline( trow[0], width, srca->pixels + (srca->rowPitch * u3), srca->rowPitch, srca->format ) if ( !_LoadScanlineLinear( trow[0], width, srca->pixels + (srca->rowPitch * u3), srca->rowPitch, srca->format, filter )
|| !_LoadScanline( trow[1], width, srcb->pixels + (srcb->rowPitch * u3), srcb->rowPitch, srcb->format ) || !_LoadScanlineLinear( trow[1], width, srcb->pixels + (srcb->rowPitch * u3), srcb->rowPitch, srcb->format, filter )
|| !_LoadScanline( trow[2], width, srcc->pixels + (srcc->rowPitch * u3), srcc->rowPitch, srcc->format ) || !_LoadScanlineLinear( trow[2], width, srcc->pixels + (srcc->rowPitch * u3), srcc->rowPitch, srcc->format, filter )
|| !_LoadScanline( trow[3], width, srcd->pixels + (srcd->rowPitch * u3), srcd->rowPitch, srcd->format ) ) || !_LoadScanlineLinear( trow[3], width, srcd->pixels + (srcd->rowPitch * u3), srcd->rowPitch, srcd->format, filter ) )
return E_FAIL; return E_FAIL;
} }
@ -1878,7 +1884,7 @@ static HRESULT _Generate3DMipsCubicFilter( _In_ size_t depth, _In_ size_t levels
CUBIC_INTERPOLATE( target[x], toZ.x, D[0], D[1], D[2], D[3] ); CUBIC_INTERPOLATE( target[x], toZ.x, D[0], D[1], D[2], D[3] );
} }
if ( !_StoreScanline( pDest, dest->rowPitch, dest->format, target, nwidth ) ) if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) )
return E_FAIL; return E_FAIL;
pDest += dest->rowPitch; pDest += dest->rowPitch;
} }
@ -1914,7 +1920,7 @@ static HRESULT _Generate3DMipsCubicFilter( _In_ size_t depth, _In_ size_t levels
{ {
u0 = toY.u0; u0 = toY.u0;
if ( !_LoadScanline( urow[0], width, pSrc + (rowPitch * u0), rowPitch, src->format ) ) if ( !_LoadScanlineLinear( urow[0], width, pSrc + (rowPitch * u0), rowPitch, src->format, filter ) )
return E_FAIL; return E_FAIL;
} }
else if ( toY.u0 == u1 ) else if ( toY.u0 == u1 )
@ -1947,7 +1953,7 @@ static HRESULT _Generate3DMipsCubicFilter( _In_ size_t depth, _In_ size_t levels
{ {
u1 = toY.u1; u1 = toY.u1;
if ( !_LoadScanline( vrow[0], width, pSrc + (rowPitch * u1), rowPitch, src->format ) ) if ( !_LoadScanlineLinear( vrow[0], width, pSrc + (rowPitch * u1), rowPitch, src->format, filter ) )
return E_FAIL; return E_FAIL;
} }
else if ( toY.u1 == u2 ) else if ( toY.u1 == u2 )
@ -1973,7 +1979,7 @@ static HRESULT _Generate3DMipsCubicFilter( _In_ size_t depth, _In_ size_t levels
{ {
u2 = toY.u2; u2 = toY.u2;
if ( !_LoadScanline( srow[0], width, pSrc + (rowPitch * u2), rowPitch, src->format ) ) if ( !_LoadScanlineLinear( srow[0], width, pSrc + (rowPitch * u2), rowPitch, src->format, filter ) )
return E_FAIL; return E_FAIL;
} }
else else
@ -1990,7 +1996,7 @@ static HRESULT _Generate3DMipsCubicFilter( _In_ size_t depth, _In_ size_t levels
{ {
u3 = toY.u3; u3 = toY.u3;
if ( !_LoadScanline( trow[0], width, pSrc + (rowPitch * u3), rowPitch, src->format ) ) if ( !_LoadScanlineLinear( trow[0], width, pSrc + (rowPitch * u3), rowPitch, src->format, filter ) )
return E_FAIL; return E_FAIL;
} }
@ -2007,7 +2013,7 @@ static HRESULT _Generate3DMipsCubicFilter( _In_ size_t depth, _In_ size_t levels
CUBIC_INTERPOLATE( target[x], toY.x, C0, C1, C2, C3 ); CUBIC_INTERPOLATE( target[x], toY.x, C0, C1, C2, C3 );
} }
if ( !_StoreScanline( pDest, dest->rowPitch, dest->format, target, nwidth ) ) if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) )
return E_FAIL; return E_FAIL;
pDest += dest->rowPitch; pDest += dest->rowPitch;
} }
@ -2143,7 +2149,7 @@ HRESULT GenerateMipMaps( const Image& baseImage, DWORD filter, size_t levels, Sc
if ( FAILED(hr) ) if ( FAILED(hr) )
return hr; return hr;
hr = _Generate2DMipsBoxFilter( levels, mipChain, 0 ); hr = _Generate2DMipsBoxFilter( levels, filter, mipChain, 0 );
if ( FAILED(hr) ) if ( FAILED(hr) )
mipChain.Release(); mipChain.Release();
return hr; return hr;
@ -2320,7 +2326,7 @@ HRESULT GenerateMipMaps( const Image* srcImages, size_t nimages, const TexMetada
for( size_t item = 0; item < metadata.arraySize; ++item ) for( size_t item = 0; item < metadata.arraySize; ++item )
{ {
hr = _Generate2DMipsBoxFilter( levels, mipChain, item ); hr = _Generate2DMipsBoxFilter( levels, filter, mipChain, item );
if ( FAILED(hr) ) if ( FAILED(hr) )
mipChain.Release(); mipChain.Release();
} }
@ -2427,7 +2433,7 @@ HRESULT GenerateMipMaps3D( const Image* baseImages, size_t depth, DWORD filter,
if ( FAILED(hr) ) if ( FAILED(hr) )
return hr; return hr;
hr = _Generate3DMipsBoxFilter( depth, levels, mipChain ); hr = _Generate3DMipsBoxFilter( depth, levels, filter, mipChain );
if ( FAILED(hr) ) if ( FAILED(hr) )
mipChain.Release(); mipChain.Release();
return hr; return hr;
@ -2525,7 +2531,7 @@ HRESULT GenerateMipMaps3D( const Image* srcImages, size_t nimages, const TexMeta
if ( FAILED(hr) ) if ( FAILED(hr) )
return hr; return hr;
hr = _Generate3DMipsBoxFilter( metadata.depth, levels, mipChain ); hr = _Generate3DMipsBoxFilter( metadata.depth, levels, filter, mipChain );
if ( FAILED(hr) ) if ( FAILED(hr) )
mipChain.Release(); mipChain.Release();
return hr; return hr;

View File

@ -185,9 +185,17 @@ namespace DirectX
bool _LoadScanline( _Out_writes_(count) XMVECTOR* pDestination, _In_ size_t count, bool _LoadScanline( _Out_writes_(count) XMVECTOR* pDestination, _In_ size_t count,
_In_reads_bytes_(size) LPCVOID pSource, _In_ size_t size, _In_ DXGI_FORMAT format ); _In_reads_bytes_(size) LPCVOID pSource, _In_ size_t size, _In_ DXGI_FORMAT format );
_Success_(return != false)
bool _LoadScanlineLinear( _Out_writes_(count) XMVECTOR* pDestination, _In_ size_t count,
_In_reads_bytes_(size) LPCVOID pSource, _In_ size_t size, _In_ DXGI_FORMAT format, _In_ DWORD flags );
_Success_(return != false) _Success_(return != false)
bool _StoreScanline( LPVOID pDestination, _In_ size_t size, _In_ DXGI_FORMAT format, bool _StoreScanline( LPVOID pDestination, _In_ size_t size, _In_ DXGI_FORMAT format,
_In_reads_(count) const XMVECTOR* pSource, _In_ size_t count ); _In_reads_(count) const XMVECTOR* pSource, _In_ size_t count);
_Success_(return != false)
bool _StoreScanlineLinear( LPVOID pDestination, _In_ size_t size, _In_ DXGI_FORMAT format,
_Inout_updates_all_(count) XMVECTOR* pSource, _In_ size_t count, _In_ DWORD flags );
HRESULT _ConvertToR32G32B32A32( _In_ const Image& srcImage, _Inout_ ScratchImage& image ); HRESULT _ConvertToR32G32B32A32( _In_ const Image& srcImage, _Inout_ ScratchImage& image );