diff --git a/DirectXTex/DirectXTex.h b/DirectXTex/DirectXTex.h index f80225c..3afb8c4 100644 --- a/DirectXTex/DirectXTex.h +++ b/DirectXTex/DirectXTex.h @@ -64,6 +64,7 @@ namespace DirectX { CP_FLAGS_NONE = 0x0, // Normal operation CP_FLAGS_LEGACY_DWORD = 0x1, // Assume pitch is DWORD aligned instead of BYTE aligned + CP_FLAGS_PARAGRAPH = 0x2, // Assume pitch is 16-byte aligned instead of BYTE aligned CP_FLAGS_24BPP = 0x10000, // Override with a legacy 24 bits-per-pixel format size CP_FLAGS_16BPP = 0x20000, // Override with a legacy 16 bits-per-pixel format size CP_FLAGS_8BPP = 0x40000, // Override with a legacy 8 bits-per-pixel format size @@ -238,17 +239,17 @@ namespace DirectX ScratchImage& operator= (ScratchImage&& moveFrom); - HRESULT Initialize( _In_ const TexMetadata& mdata ); + HRESULT Initialize( _In_ const TexMetadata& mdata, _In_ DWORD flags = CP_FLAGS_NONE ); - HRESULT Initialize1D( _In_ DXGI_FORMAT fmt, _In_ size_t length, _In_ size_t arraySize, _In_ size_t mipLevels ); - HRESULT Initialize2D( _In_ DXGI_FORMAT fmt, _In_ size_t width, _In_ size_t height, _In_ size_t arraySize, _In_ size_t mipLevels ); - HRESULT Initialize3D( _In_ DXGI_FORMAT fmt, _In_ size_t width, _In_ size_t height, _In_ size_t depth, _In_ size_t mipLevels ); - HRESULT InitializeCube( _In_ DXGI_FORMAT fmt, _In_ size_t width, _In_ size_t height, _In_ size_t nCubes, _In_ size_t mipLevels ); + HRESULT Initialize1D( _In_ DXGI_FORMAT fmt, _In_ size_t length, _In_ size_t arraySize, _In_ size_t mipLevels, _In_ DWORD flags = CP_FLAGS_NONE ); + HRESULT Initialize2D( _In_ DXGI_FORMAT fmt, _In_ size_t width, _In_ size_t height, _In_ size_t arraySize, _In_ size_t mipLevels, _In_ DWORD flags = CP_FLAGS_NONE ); + HRESULT Initialize3D( _In_ DXGI_FORMAT fmt, _In_ size_t width, _In_ size_t height, _In_ size_t depth, _In_ size_t mipLevels, _In_ DWORD flags = CP_FLAGS_NONE ); + HRESULT InitializeCube( _In_ DXGI_FORMAT fmt, _In_ size_t width, _In_ size_t height, _In_ size_t nCubes, _In_ size_t mipLevels, _In_ DWORD flags = CP_FLAGS_NONE ); - HRESULT InitializeFromImage( _In_ const Image& srcImage, _In_ bool allow1D = false ); - HRESULT InitializeArrayFromImages( _In_reads_(nImages) const Image* images, _In_ size_t nImages, _In_ bool allow1D = false ); - HRESULT InitializeCubeFromImages( _In_reads_(nImages) const Image* images, _In_ size_t nImages ); - HRESULT Initialize3DFromImages( _In_reads_(depth) const Image* images, _In_ size_t depth ); + HRESULT InitializeFromImage( _In_ const Image& srcImage, _In_ bool allow1D = false, _In_ DWORD flags = CP_FLAGS_NONE ); + HRESULT InitializeArrayFromImages( _In_reads_(nImages) const Image* images, _In_ size_t nImages, _In_ bool allow1D = false, _In_ DWORD flags = CP_FLAGS_NONE ); + HRESULT InitializeCubeFromImages( _In_reads_(nImages) const Image* images, _In_ size_t nImages, _In_ DWORD flags = CP_FLAGS_NONE ); + HRESULT Initialize3DFromImages( _In_reads_(depth) const Image* images, _In_ size_t depth, _In_ DWORD flags = CP_FLAGS_NONE ); void Release(); diff --git a/DirectXTex/DirectXTexDDS.cpp b/DirectXTex/DirectXTexDDS.cpp index 00a4208..5fc2191 100644 --- a/DirectXTex/DirectXTexDDS.cpp +++ b/DirectXTex/DirectXTexDDS.cpp @@ -1619,11 +1619,28 @@ HRESULT SaveToDDSMemory( const Image* images, size_t nimages, const TexMetadata& if ( FAILED(hr) ) return hr; + bool fastpath = true; + for( size_t i = 0; i < nimages; ++i ) { - required += images[ i ].slicePitch; if ( !images[ i ].pixels ) return E_POINTER; + + if ( images[ i ].format != metadata.format ) + return E_FAIL; + + size_t ddsRowPitch, ddsSlicePitch; + ComputePitch( metadata.format, images[ i ].width, images[ i ].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE ); + + assert( images[ i ].rowPitch > 0 ); + assert( images[ i ].slicePitch > 0 ); + + if ( ( images[ i ].rowPitch != ddsRowPitch ) || ( images[ i ].slicePitch != ddsSlicePitch ) ) + { + fastpath = false; + } + + required += ddsSlicePitch; } assert( required > 0 ); @@ -1669,14 +1686,47 @@ HRESULT SaveToDDSMemory( const Image* images, size_t nimages, const TexMetadata& return E_FAIL; } - size_t pixsize = images[ index ].slicePitch; - if ( memcpy_s( pDestination, remaining, images[ index ].pixels, pixsize ) ) + if ( fastpath ) { - blob.Release(); - return E_FAIL; + size_t pixsize = images[ index ].slicePitch; + if ( memcpy_s( pDestination, remaining, images[ index ].pixels, pixsize ) ) + { + blob.Release(); + return E_FAIL; + } + + pDestination += pixsize; + remaining -= pixsize; + } + else + { + size_t ddsRowPitch, ddsSlicePitch; + ComputePitch( metadata.format, images[ index ].width, images[ index ].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE ); + + size_t rowPitch = images[ index ].rowPitch; + + const uint8_t * __restrict sPtr = reinterpret_cast(images[ index ].pixels); + uint8_t * __restrict dPtr = reinterpret_cast(pDestination); + + size_t lines = ComputeScanlines( metadata.format, images[ index ].height ); + size_t csize = std::min( rowPitch, ddsRowPitch ); + size_t tremaining = remaining; + for( size_t j = 0; j < lines; ++j ) + { + if ( memcpy_s( dPtr, tremaining, sPtr, csize ) ) + { + blob.Release(); + return E_FAIL; + } + + sPtr += rowPitch; + dPtr += ddsRowPitch; + tremaining -= ddsRowPitch; + } + + pDestination += ddsSlicePitch; + remaining -= ddsSlicePitch; } - pDestination += pixsize; - remaining -= pixsize; ++index; } @@ -1705,14 +1755,47 @@ HRESULT SaveToDDSMemory( const Image* images, size_t nimages, const TexMetadata& return E_FAIL; } - size_t pixsize = images[ index ].slicePitch; - if ( memcpy_s( pDestination, remaining, images[ index ].pixels, pixsize ) ) + if ( fastpath ) { - blob.Release(); - return E_FAIL; + size_t pixsize = images[ index ].slicePitch; + if ( memcpy_s( pDestination, remaining, images[ index ].pixels, pixsize ) ) + { + blob.Release(); + return E_FAIL; + } + + pDestination += pixsize; + remaining -= pixsize; + } + else + { + size_t ddsRowPitch, ddsSlicePitch; + ComputePitch( metadata.format, images[ index ].width, images[ index ].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE ); + + size_t rowPitch = images[ index ].rowPitch; + + const uint8_t * __restrict sPtr = reinterpret_cast(images[ index ].pixels); + uint8_t * __restrict dPtr = reinterpret_cast(pDestination); + + size_t lines = ComputeScanlines( metadata.format, images[ index ].height ); + size_t csize = std::min( rowPitch, ddsRowPitch ); + size_t tremaining = remaining; + for( size_t j = 0; j < lines; ++j ) + { + if ( memcpy_s( dPtr, tremaining, sPtr, csize ) ) + { + blob.Release(); + return E_FAIL; + } + + sPtr += rowPitch; + dPtr += ddsRowPitch; + tremaining -= ddsRowPitch; + } + + pDestination += ddsSlicePitch; + remaining -= ddsSlicePitch; } - pDestination += pixsize; - remaining -= pixsize; ++index; } @@ -1788,16 +1871,50 @@ HRESULT SaveToDDSFile( const Image* images, size_t nimages, const TexMetadata& m if ( !images[ index ].pixels ) return E_POINTER; - size_t pixsize = images[ index ].slicePitch; + assert( images[ index ].rowPitch > 0 ); + assert( images[ index ].slicePitch > 0 ); - if ( !WriteFile( hFile.get(), images[ index ].pixels, static_cast( pixsize ), &bytesWritten, 0 ) ) + size_t ddsRowPitch, ddsSlicePitch; + ComputePitch( metadata.format, images[ index ].width, images[ index ].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE ); + + if ( images[ index ].slicePitch == ddsSlicePitch ) { - return HRESULT_FROM_WIN32( GetLastError() ); + if ( !WriteFile( hFile.get(), images[ index ].pixels, static_cast( ddsSlicePitch ), &bytesWritten, 0 ) ) + { + return HRESULT_FROM_WIN32( GetLastError() ); + } + + if ( bytesWritten != ddsSlicePitch ) + { + return E_FAIL; + } } - - if ( bytesWritten != pixsize ) + else { - return E_FAIL; + size_t rowPitch = images[ index ].rowPitch; + if ( rowPitch < ddsRowPitch ) + { + // DDS uses 1-byte alignment, so if this is happening then the input pitch isn't actually a full line of data + return E_FAIL; + } + + const uint8_t * __restrict sPtr = reinterpret_cast(images[ index ].pixels); + + size_t lines = ComputeScanlines( metadata.format, images[ index ].height ); + for( size_t j = 0; j < lines; ++j ) + { + if ( !WriteFile( hFile.get(), sPtr, static_cast( ddsRowPitch ), &bytesWritten, 0 ) ) + { + return HRESULT_FROM_WIN32( GetLastError() ); + } + + if ( bytesWritten != ddsRowPitch ) + { + return E_FAIL; + } + + sPtr += rowPitch; + } } } } @@ -1822,16 +1939,50 @@ HRESULT SaveToDDSFile( const Image* images, size_t nimages, const TexMetadata& m if ( !images[ index ].pixels ) return E_POINTER; - size_t pixsize = images[ index ].slicePitch; + assert( images[ index ].rowPitch > 0 ); + assert( images[ index ].slicePitch > 0 ); - if ( !WriteFile( hFile.get(), images[ index ].pixels, static_cast( pixsize ), &bytesWritten, 0 ) ) + size_t ddsRowPitch, ddsSlicePitch; + ComputePitch( metadata.format, images[ index ].width, images[ index ].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE ); + + if ( images[ index ].slicePitch == ddsSlicePitch ) { - return HRESULT_FROM_WIN32( GetLastError() ); + if ( !WriteFile( hFile.get(), images[ index ].pixels, static_cast( ddsSlicePitch ), &bytesWritten, 0 ) ) + { + return HRESULT_FROM_WIN32( GetLastError() ); + } + + if ( bytesWritten != ddsSlicePitch ) + { + return E_FAIL; + } } - - if ( bytesWritten != pixsize ) + else { - return E_FAIL; + size_t rowPitch = images[ index ].rowPitch; + if ( rowPitch < ddsRowPitch ) + { + // DDS uses 1-byte alignment, so if this is happening then the input pitch isn't actually a full line of data + return E_FAIL; + } + + const uint8_t * __restrict sPtr = reinterpret_cast(images[ index ].pixels); + + size_t lines = ComputeScanlines( metadata.format, images[ index ].height ); + for( size_t j = 0; j < lines; ++j ) + { + if ( !WriteFile( hFile.get(), sPtr, static_cast( ddsRowPitch ), &bytesWritten, 0 ) ) + { + return HRESULT_FROM_WIN32( GetLastError() ); + } + + if ( bytesWritten != ddsRowPitch ) + { + return E_FAIL; + } + + sPtr += rowPitch; + } } } diff --git a/DirectXTex/DirectXTexImage.cpp b/DirectXTex/DirectXTexImage.cpp index 7993258..f754034 100644 --- a/DirectXTex/DirectXTexImage.cpp +++ b/DirectXTex/DirectXTexImage.cpp @@ -254,7 +254,7 @@ ScratchImage& ScratchImage::operator= (ScratchImage&& moveFrom) // Methods //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT ScratchImage::Initialize( const TexMetadata& mdata ) +HRESULT ScratchImage::Initialize( const TexMetadata& mdata, DWORD flags ) { if ( !IsValid(mdata.format) ) return E_INVALIDARG; @@ -322,7 +322,7 @@ HRESULT ScratchImage::Initialize( const TexMetadata& mdata ) _metadata.dimension = mdata.dimension; size_t pixelSize, nimages; - _DetermineImageArray( _metadata, CP_FLAGS_NONE, nimages, pixelSize ); + _DetermineImageArray( _metadata, flags, nimages, pixelSize ); _image = new (std::nothrow) Image[ nimages ]; if ( !_image ) @@ -338,7 +338,7 @@ HRESULT ScratchImage::Initialize( const TexMetadata& mdata ) return E_OUTOFMEMORY; } _size = pixelSize; - if ( !_SetupImageArray( _memory, pixelSize, _metadata, CP_FLAGS_NONE, _image, nimages ) ) + if ( !_SetupImageArray( _memory, pixelSize, _metadata, flags, _image, nimages ) ) { Release(); return E_FAIL; @@ -348,7 +348,7 @@ HRESULT ScratchImage::Initialize( const TexMetadata& mdata ) } _Use_decl_annotations_ -HRESULT ScratchImage::Initialize1D( DXGI_FORMAT fmt, size_t length, size_t arraySize, size_t mipLevels ) +HRESULT ScratchImage::Initialize1D( DXGI_FORMAT fmt, size_t length, size_t arraySize, size_t mipLevels, DWORD flags ) { if ( !length || !arraySize ) return E_INVALIDARG; @@ -357,7 +357,7 @@ HRESULT ScratchImage::Initialize1D( DXGI_FORMAT fmt, size_t length, size_t array return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); // 1D is a special case of the 2D case - HRESULT hr = Initialize2D( fmt, length, 1, arraySize, mipLevels ); + HRESULT hr = Initialize2D( fmt, length, 1, arraySize, mipLevels, flags ); if ( FAILED(hr) ) return hr; @@ -367,7 +367,7 @@ HRESULT ScratchImage::Initialize1D( DXGI_FORMAT fmt, size_t length, size_t array } _Use_decl_annotations_ -HRESULT ScratchImage::Initialize2D( DXGI_FORMAT fmt, size_t width, size_t height, size_t arraySize, size_t mipLevels ) +HRESULT ScratchImage::Initialize2D( DXGI_FORMAT fmt, size_t width, size_t height, size_t arraySize, size_t mipLevels, DWORD flags ) { if ( !IsValid(fmt) || !width || !height || !arraySize ) return E_INVALIDARG; @@ -391,7 +391,7 @@ HRESULT ScratchImage::Initialize2D( DXGI_FORMAT fmt, size_t width, size_t height _metadata.dimension = TEX_DIMENSION_TEXTURE2D; size_t pixelSize, nimages; - _DetermineImageArray( _metadata, CP_FLAGS_NONE, nimages, pixelSize ); + _DetermineImageArray( _metadata, flags, nimages, pixelSize ); _image = new (std::nothrow) Image[ nimages ]; if ( !_image ) @@ -407,7 +407,7 @@ HRESULT ScratchImage::Initialize2D( DXGI_FORMAT fmt, size_t width, size_t height return E_OUTOFMEMORY; } _size = pixelSize; - if ( !_SetupImageArray( _memory, pixelSize, _metadata, CP_FLAGS_NONE, _image, nimages ) ) + if ( !_SetupImageArray( _memory, pixelSize, _metadata, flags, _image, nimages ) ) { Release(); return E_FAIL; @@ -417,7 +417,7 @@ HRESULT ScratchImage::Initialize2D( DXGI_FORMAT fmt, size_t width, size_t height } _Use_decl_annotations_ -HRESULT ScratchImage::Initialize3D( DXGI_FORMAT fmt, size_t width, size_t height, size_t depth, size_t mipLevels ) +HRESULT ScratchImage::Initialize3D( DXGI_FORMAT fmt, size_t width, size_t height, size_t depth, size_t mipLevels, DWORD flags ) { if ( !IsValid(fmt) || !width || !height || !depth ) return E_INVALIDARG; @@ -441,7 +441,7 @@ HRESULT ScratchImage::Initialize3D( DXGI_FORMAT fmt, size_t width, size_t height _metadata.dimension = TEX_DIMENSION_TEXTURE3D; size_t pixelSize, nimages; - _DetermineImageArray( _metadata, CP_FLAGS_NONE, nimages, pixelSize ); + _DetermineImageArray( _metadata, flags, nimages, pixelSize ); _image = new (std::nothrow) Image[ nimages ]; if ( !_image ) @@ -460,7 +460,7 @@ HRESULT ScratchImage::Initialize3D( DXGI_FORMAT fmt, size_t width, size_t height } _size = pixelSize; - if ( !_SetupImageArray( _memory, pixelSize, _metadata, CP_FLAGS_NONE, _image, nimages ) ) + if ( !_SetupImageArray( _memory, pixelSize, _metadata, flags, _image, nimages ) ) { Release(); return E_FAIL; @@ -470,7 +470,7 @@ HRESULT ScratchImage::Initialize3D( DXGI_FORMAT fmt, size_t width, size_t height } _Use_decl_annotations_ -HRESULT ScratchImage::InitializeCube( DXGI_FORMAT fmt, size_t width, size_t height, size_t nCubes, size_t mipLevels ) +HRESULT ScratchImage::InitializeCube( DXGI_FORMAT fmt, size_t width, size_t height, size_t nCubes, size_t mipLevels, DWORD flags ) { if ( !width || !height || !nCubes ) return E_INVALIDARG; @@ -479,7 +479,7 @@ HRESULT ScratchImage::InitializeCube( DXGI_FORMAT fmt, size_t width, size_t heig return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); // A DirectX11 cubemap is just a 2D texture array that is a multiple of 6 for each cube - HRESULT hr = Initialize2D( fmt, width, height, nCubes * 6, mipLevels ); + HRESULT hr = Initialize2D( fmt, width, height, nCubes * 6, mipLevels, flags ); if ( FAILED(hr) ) return hr; @@ -489,11 +489,11 @@ HRESULT ScratchImage::InitializeCube( DXGI_FORMAT fmt, size_t width, size_t heig } _Use_decl_annotations_ -HRESULT ScratchImage::InitializeFromImage( const Image& srcImage, bool allow1D ) +HRESULT ScratchImage::InitializeFromImage( const Image& srcImage, bool allow1D, DWORD flags ) { HRESULT hr = ( srcImage.height > 1 || !allow1D ) - ? Initialize2D( srcImage.format, srcImage.width, srcImage.height, 1, 1 ) - : Initialize1D( srcImage.format, srcImage.width, 1, 1 ); + ? Initialize2D( srcImage.format, srcImage.width, srcImage.height, 1, 1, flags ) + : Initialize1D( srcImage.format, srcImage.width, 1, 1, flags ); if ( FAILED(hr) ) return hr; @@ -526,7 +526,7 @@ HRESULT ScratchImage::InitializeFromImage( const Image& srcImage, bool allow1D ) } _Use_decl_annotations_ -HRESULT ScratchImage::InitializeArrayFromImages( const Image* images, size_t nImages, bool allow1D ) +HRESULT ScratchImage::InitializeArrayFromImages( const Image* images, size_t nImages, bool allow1D, DWORD flags ) { if ( !images || !nImages ) return E_INVALIDARG; @@ -548,8 +548,8 @@ HRESULT ScratchImage::InitializeArrayFromImages( const Image* images, size_t nIm } HRESULT hr = ( height > 1 || !allow1D ) - ? Initialize2D( format, width, height, nImages, 1 ) - : Initialize1D( format, width, nImages, 1 ); + ? Initialize2D( format, width, height, nImages, 1, flags ) + : Initialize1D( format, width, nImages, 1, flags ); if ( FAILED(hr) ) return hr; @@ -586,7 +586,7 @@ HRESULT ScratchImage::InitializeArrayFromImages( const Image* images, size_t nIm } _Use_decl_annotations_ -HRESULT ScratchImage::InitializeCubeFromImages( const Image* images, size_t nImages ) +HRESULT ScratchImage::InitializeCubeFromImages( const Image* images, size_t nImages, DWORD flags ) { if ( !images || !nImages ) return E_INVALIDARG; @@ -598,7 +598,7 @@ HRESULT ScratchImage::InitializeCubeFromImages( const Image* images, size_t nIma if ( IsVideo(images[0].format) || IsPalettized(images[0].format) ) return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); - HRESULT hr = InitializeArrayFromImages( images, nImages, false ); + HRESULT hr = InitializeArrayFromImages( images, nImages, false, flags ); if ( FAILED(hr) ) return hr; @@ -608,7 +608,7 @@ HRESULT ScratchImage::InitializeCubeFromImages( const Image* images, size_t nIma } _Use_decl_annotations_ -HRESULT ScratchImage::Initialize3DFromImages( const Image* images, size_t depth ) +HRESULT ScratchImage::Initialize3DFromImages( const Image* images, size_t depth, DWORD flags ) { if ( !images || !depth ) return E_INVALIDARG; @@ -629,7 +629,7 @@ HRESULT ScratchImage::Initialize3DFromImages( const Image* images, size_t depth } } - HRESULT hr = Initialize3D( format, width, height, depth, 1 ); + HRESULT hr = Initialize3D( format, width, height, depth, 1, flags ); if ( FAILED(hr) ) return hr; diff --git a/DirectXTex/DirectXTexUtil.cpp b/DirectXTex/DirectXTexUtil.cpp index d98626b..5a343fd 100644 --- a/DirectXTex/DirectXTexUtil.cpp +++ b/DirectXTex/DirectXTexUtil.cpp @@ -661,6 +661,11 @@ void ComputePitch( DXGI_FORMAT fmt, size_t width, size_t height, rowPitch = ( ( width * bpp + 31 ) / 32 ) * sizeof(uint32_t); slicePitch = rowPitch * height; } + else if ( flags & CP_FLAGS_PARAGRAPH ) + { + rowPitch = ( ( width * bpp + 127 ) / 128 ) * 16; + slicePitch = rowPitch * height; + } else { rowPitch = ( width * bpp + 7 ) / 8;