static HRESULT _PremultiplyAlpha( _In_ const Image& srcImage, _In_ const Image& destImage ) { assert( srcImage.width == destImage.width ); assert( srcImage.height == destImage.height ); ScopedAlignedArrayXMVECTOR scanline( reinterpret_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; if ( !pSrc || !pDest ) return E_POINTER; for( size_t h = 0; h < srcImage.height; ++h ) { if ( !_LoadScanline( scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) ) return E_FAIL; XMVECTOR* ptr = scanline.get(); for( size_t w = 0; w < srcImage.width; ++w ) { XMVECTOR v = *ptr; XMVECTOR alpha = XMVectorSplatW( *ptr ); alpha = XMVectorMultiply( v, alpha ); *(ptr++) = XMVectorSelect( v, alpha, g_XMSelect1110 ); } if ( !_StoreScanline( pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width ) ) return E_FAIL; pSrc += srcImage.rowPitch; pDest += destImage.rowPitch; } return S_OK; }
//------------------------------------------------------------------------------------- static HRESULT _DecompressBC( _In_ const Image& cImage, _In_ const Image& result ) { if ( !cImage.pixels || !result.pixels ) return E_POINTER; assert( cImage.width == result.width ); assert( cImage.height == result.height ); // Image must be a multiple of 4 (degenerate cases of 1x1, 1x2, 2x1, and 2x2 are allowed) size_t width = cImage.width; if ( (width % 4) != 0 ) { if ( width != 1 && width != 2 ) return E_INVALIDARG; } size_t height = cImage.height; if ( (height % 4) != 0 ) { if ( height != 1 && height != 2 ) return E_INVALIDARG; } const DXGI_FORMAT format = result.format; size_t dbpp = BitsPerPixel( format ); if ( !dbpp ) return E_FAIL; if ( dbpp < 8 ) { // We don't support decompressing to monochrome (DXGI_FORMAT_R1_UNORM) return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); } // Round to bytes dbpp = ( dbpp + 7 ) / 8; uint8_t *pDest = result.pixels; if ( !pDest ) return E_POINTER; // Promote "typeless" BC formats DXGI_FORMAT cformat; switch( cImage.format ) { case DXGI_FORMAT_BC1_TYPELESS: cformat = DXGI_FORMAT_BC1_UNORM; break; case DXGI_FORMAT_BC2_TYPELESS: cformat = DXGI_FORMAT_BC2_UNORM; break; case DXGI_FORMAT_BC3_TYPELESS: cformat = DXGI_FORMAT_BC3_UNORM; break; case DXGI_FORMAT_BC4_TYPELESS: cformat = DXGI_FORMAT_BC4_UNORM; break; case DXGI_FORMAT_BC5_TYPELESS: cformat = DXGI_FORMAT_BC5_UNORM; break; case DXGI_FORMAT_BC6H_TYPELESS: cformat = DXGI_FORMAT_BC6H_UF16; break; case DXGI_FORMAT_BC7_TYPELESS: cformat = DXGI_FORMAT_BC7_UNORM; break; default: cformat = cImage.format; break; } // Determine BC format decoder BC_DECODE pfDecode; size_t sbpp; switch(cformat) { case DXGI_FORMAT_BC1_UNORM: case DXGI_FORMAT_BC1_UNORM_SRGB: pfDecode = D3DXDecodeBC1; sbpp = 8; break; case DXGI_FORMAT_BC2_UNORM: case DXGI_FORMAT_BC2_UNORM_SRGB: pfDecode = D3DXDecodeBC2; sbpp = 16; break; case DXGI_FORMAT_BC3_UNORM: case DXGI_FORMAT_BC3_UNORM_SRGB: pfDecode = D3DXDecodeBC3; sbpp = 16; break; case DXGI_FORMAT_BC4_UNORM: pfDecode = D3DXDecodeBC4U; sbpp = 8; break; case DXGI_FORMAT_BC4_SNORM: pfDecode = D3DXDecodeBC4S; sbpp = 8; break; case DXGI_FORMAT_BC5_UNORM: pfDecode = D3DXDecodeBC5U; sbpp = 16; break; case DXGI_FORMAT_BC5_SNORM: pfDecode = D3DXDecodeBC5S; sbpp = 16; break; case DXGI_FORMAT_BC6H_UF16: pfDecode = D3DXDecodeBC6HU; sbpp = 16; break; case DXGI_FORMAT_BC6H_SF16: pfDecode = D3DXDecodeBC6HS; sbpp = 16; break; case DXGI_FORMAT_BC7_UNORM: case DXGI_FORMAT_BC7_UNORM_SRGB: pfDecode = D3DXDecodeBC7; sbpp = 16; break; default: return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); } XMVECTOR temp[16]; const uint8_t *pSrc = cImage.pixels; const size_t rowPitch = result.rowPitch; for( size_t h=0; h < cImage.height; h += 4 ) { const uint8_t *sptr = pSrc; uint8_t* dptr = pDest; for( size_t count = 0; count < cImage.rowPitch; count += sbpp ) { pfDecode( temp, sptr ); _ConvertScanline( temp, 16, format, cformat, 0 ); if ( !_StoreScanline( dptr, rowPitch, format, &temp[0], 4 ) ) return E_FAIL; if ( result.height > 1 ) { if ( !_StoreScanline( dptr + rowPitch, rowPitch, format, &temp[4], 4 ) ) return E_FAIL; if ( result.height > 2 ) { if ( !_StoreScanline( dptr + rowPitch*2, rowPitch, format, &temp[8], 4 ) ) return E_FAIL; if ( !_StoreScanline( dptr + rowPitch*3, rowPitch, format, &temp[12], 4 ) ) return E_FAIL; } } sptr += sbpp; dptr += dbpp*4; } pSrc += cImage.rowPitch; pDest += rowPitch*4; } return S_OK; }
//------------------------------------------------------------------------------------- static HRESULT _DecompressBC( _In_ const Image& cImage, _In_ const Image& result ) { if ( !cImage.pixels || !result.pixels ) return E_POINTER; assert( cImage.width == result.width ); assert( cImage.height == result.height ); const DXGI_FORMAT format = result.format; size_t dbpp = BitsPerPixel( format ); if ( !dbpp ) return E_FAIL; if ( dbpp < 8 ) { // We don't support decompressing to monochrome (DXGI_FORMAT_R1_UNORM) return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); } // Round to bytes dbpp = ( dbpp + 7 ) / 8; uint8_t *pDest = result.pixels; if ( !pDest ) return E_POINTER; // Promote "typeless" BC formats DXGI_FORMAT cformat; switch( cImage.format ) { case DXGI_FORMAT_BC1_TYPELESS: cformat = DXGI_FORMAT_BC1_UNORM; break; case DXGI_FORMAT_BC2_TYPELESS: cformat = DXGI_FORMAT_BC2_UNORM; break; case DXGI_FORMAT_BC3_TYPELESS: cformat = DXGI_FORMAT_BC3_UNORM; break; case DXGI_FORMAT_BC4_TYPELESS: cformat = DXGI_FORMAT_BC4_UNORM; break; case DXGI_FORMAT_BC5_TYPELESS: cformat = DXGI_FORMAT_BC5_UNORM; break; case DXGI_FORMAT_BC6H_TYPELESS: cformat = DXGI_FORMAT_BC6H_UF16; break; case DXGI_FORMAT_BC7_TYPELESS: cformat = DXGI_FORMAT_BC7_UNORM; break; default: cformat = cImage.format; break; } // Determine BC format decoder BC_DECODE pfDecode; size_t sbpp; switch(cformat) { case DXGI_FORMAT_BC1_UNORM: case DXGI_FORMAT_BC1_UNORM_SRGB: pfDecode = D3DXDecodeBC1; sbpp = 8; break; case DXGI_FORMAT_BC2_UNORM: case DXGI_FORMAT_BC2_UNORM_SRGB: pfDecode = D3DXDecodeBC2; sbpp = 16; break; case DXGI_FORMAT_BC3_UNORM: case DXGI_FORMAT_BC3_UNORM_SRGB: pfDecode = D3DXDecodeBC3; sbpp = 16; break; case DXGI_FORMAT_BC4_UNORM: pfDecode = D3DXDecodeBC4U; sbpp = 8; break; case DXGI_FORMAT_BC4_SNORM: pfDecode = D3DXDecodeBC4S; sbpp = 8; break; case DXGI_FORMAT_BC5_UNORM: pfDecode = D3DXDecodeBC5U; sbpp = 16; break; case DXGI_FORMAT_BC5_SNORM: pfDecode = D3DXDecodeBC5S; sbpp = 16; break; case DXGI_FORMAT_BC6H_UF16: pfDecode = D3DXDecodeBC6HU; sbpp = 16; break; case DXGI_FORMAT_BC6H_SF16: pfDecode = D3DXDecodeBC6HS; sbpp = 16; break; case DXGI_FORMAT_BC7_UNORM: case DXGI_FORMAT_BC7_UNORM_SRGB: pfDecode = D3DXDecodeBC7; sbpp = 16; break; default: return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); } XMVECTOR temp[16]; const uint8_t *pSrc = cImage.pixels; const size_t rowPitch = result.rowPitch; for( size_t h=0; h < cImage.height; h += 4 ) { const uint8_t *sptr = pSrc; uint8_t* dptr = pDest; size_t ph = std::min<size_t>( 4, cImage.height - h ); size_t w = 0; for( size_t count = 0; count < cImage.rowPitch; count += sbpp, w += 4 ) { pfDecode( temp, sptr ); _ConvertScanline( temp, 16, format, cformat, 0 ); size_t pw = std::min<size_t>( 4, cImage.width - w ); assert( pw > 0 && ph > 0 ); if ( !_StoreScanline( dptr, rowPitch, format, &temp[0], pw ) ) return E_FAIL; if ( ph > 1 ) { if ( !_StoreScanline( dptr + rowPitch, rowPitch, format, &temp[4], pw ) ) return E_FAIL; if ( ph > 2 ) { if ( !_StoreScanline( dptr + rowPitch*2, rowPitch, format, &temp[8], pw ) ) return E_FAIL; if ( ph > 3 ) { if ( !_StoreScanline( dptr + rowPitch*3, rowPitch, format, &temp[12], pw ) ) return E_FAIL; } } } sptr += sbpp; dptr += dbpp*4; } pSrc += cImage.rowPitch; pDest += rowPitch*4; } return S_OK; }