From 5336f904daa55a986019cc29663cb3d943ddb176 Mon Sep 17 00:00:00 2001 From: walbourn_cp Date: Fri, 14 Feb 2014 13:33:01 -0800 Subject: [PATCH] DirectXTex: Support for Direct3D 11 video and Xbox One extended formats - New APIs: IsPlanar, IsPalettized, IsDepthStencil, ConvertToSinglePlane --- DirectXTex/DDS.h | 3 + DirectXTex/DirectXTex.h | 10 +- DirectXTex/DirectXTex.inl | 134 +++- DirectXTex/DirectXTexCompress.cpp | 38 +- DirectXTex/DirectXTexCompressGPU.cpp | 12 +- DirectXTex/DirectXTexConvert.cpp | 1073 +++++++++++++++++++++++++- DirectXTex/DirectXTexD3D11.cpp | 13 +- DirectXTex/DirectXTexDDS.cpp | 42 +- DirectXTex/DirectXTexImage.cpp | 93 ++- DirectXTex/DirectXTexMipmaps.cpp | 23 +- DirectXTex/DirectXTexMisc.cpp | 8 +- DirectXTex/DirectXTexNormalMaps.cpp | 20 +- DirectXTex/DirectXTexP.h | 1 + DirectXTex/DirectXTexPMAlpha.cpp | 6 +- DirectXTex/DirectXTexTGA.cpp | 2 - DirectXTex/DirectXTexUtil.cpp | 86 ++- Texconv/texconv.cpp | 56 +- 17 files changed, 1491 insertions(+), 129 deletions(-) diff --git a/DirectXTex/DDS.h b/DirectXTex/DDS.h index f3b9816..4ca6e8d 100644 --- a/DirectXTex/DDS.h +++ b/DirectXTex/DDS.h @@ -100,6 +100,9 @@ extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_R8G8_B8G8 = extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_G8R8_G8B8 = { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('G','R','G','B'), 0, 0, 0, 0, 0 }; +extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_YUY2 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('Y','U','Y','2'), 0, 0, 0, 0, 0 }; + extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A8R8G8B8 = { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }; diff --git a/DirectXTex/DirectXTex.h b/DirectXTex/DirectXTex.h index 2d5ba34..2105ded 100644 --- a/DirectXTex/DirectXTex.h +++ b/DirectXTex/DirectXTex.h @@ -37,7 +37,7 @@ #include -#define DIRECTX_TEX_VERSION 120 +#define DIRECTX_TEX_VERSION 130 namespace DirectX { @@ -48,6 +48,9 @@ namespace DirectX bool IsCompressed( _In_ DXGI_FORMAT fmt ); bool IsPacked( _In_ DXGI_FORMAT fmt ); bool IsVideo( _In_ DXGI_FORMAT fmt ); + bool IsPlanar( _In_ DXGI_FORMAT fmt ); + bool IsPalettized( _In_ DXGI_FORMAT fmt ); + bool IsDepthStencil(_In_ DXGI_FORMAT fmt ); bool IsSRGB( _In_ DXGI_FORMAT fmt ); bool IsTypeless( _In_ DXGI_FORMAT fmt, _In_ bool partialTypeless = true ); @@ -437,6 +440,11 @@ namespace DirectX _In_ DXGI_FORMAT format, _In_ DWORD filter, _In_ float threshold, _Out_ ScratchImage& result ); // Convert the image to a new format + HRESULT ConvertToSinglePlane( _In_ const Image& srcImage, _Out_ ScratchImage& image ); + HRESULT ConvertToSinglePlane( _In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata, + _Out_ ScratchImage& image ); + // Converts the image from a planar format to an equivalent non-planar format + HRESULT GenerateMipMaps( _In_ const Image& baseImage, _In_ DWORD filter, _In_ size_t levels, _Inout_ ScratchImage& mipChain, _In_ bool allow1D = false ); HRESULT GenerateMipMaps( _In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata, diff --git a/DirectXTex/DirectXTex.inl b/DirectXTex/DirectXTex.inl index 8e19d1b..a10c03d 100644 --- a/DirectXTex/DirectXTex.inl +++ b/DirectXTex/DirectXTex.inl @@ -24,7 +24,7 @@ _Use_decl_annotations_ inline bool IsValid( DXGI_FORMAT fmt ) { - return ( static_cast(fmt) >= 1 && static_cast(fmt) <= 115 ); + return ( static_cast(fmt) >= 1 && static_cast(fmt) <= 120 ); } _Use_decl_annotations_ @@ -63,9 +63,58 @@ inline bool IsCompressed( DXGI_FORMAT fmt ) _Use_decl_annotations_ inline bool IsPacked( DXGI_FORMAT fmt ) { - return ( (fmt == DXGI_FORMAT_R8G8_B8G8_UNORM) || (fmt == DXGI_FORMAT_G8R8_G8B8_UNORM) ); + switch( fmt ) + { + case DXGI_FORMAT_R8G8_B8G8_UNORM: + case DXGI_FORMAT_G8R8_G8B8_UNORM: + case DXGI_FORMAT_YUY2: // 4:2:2 8-bit + case DXGI_FORMAT_Y210: // 4:2:2 10-bit + case DXGI_FORMAT_Y216: // 4:2:2 16-bit + return true; + + default: + return false; + } } +_Use_decl_annotations_ +inline bool IsPlanar( DXGI_FORMAT fmt ) +{ + switch ( static_cast(fmt) ) + { + case DXGI_FORMAT_NV12: // 4:2:0 8-bit + case DXGI_FORMAT_P010: // 4:2:0 10-bit + case DXGI_FORMAT_P016: // 4:2:0 16-bit + case DXGI_FORMAT_420_OPAQUE:// 4:2:0 8-bit + case DXGI_FORMAT_NV11: // 4:1:1 8-bit + return true; + + case 118 /* DXGI_FORMAT_D16_UNORM_S8_UINT */: + case 119 /* DXGI_FORMAT_R16_UNORM_X8_TYPELESS */: + case 120 /* DXGI_FORMAT_X16_TYPELESS_G8_UINT */: + // These are Xbox One platform specific types + return true; + + default: + return false; + } +} + +_Use_decl_annotations_ +inline bool IsPalettized( DXGI_FORMAT fmt ) +{ + switch( fmt ) + { + case DXGI_FORMAT_AI44: + case DXGI_FORMAT_IA44: + case DXGI_FORMAT_P8: + case DXGI_FORMAT_A8P8: + return true; + + default: + return false; + } +} _Use_decl_annotations_ inline bool IsVideo( DXGI_FORMAT fmt ) @@ -83,7 +132,6 @@ inline bool IsVideo( DXGI_FORMAT fmt ) case DXGI_FORMAT_Y216: case DXGI_FORMAT_NV11: // These video formats can be used with the 3D pipeline through special view mappings - return true; case DXGI_FORMAT_420_OPAQUE: case DXGI_FORMAT_AI44: @@ -98,6 +146,29 @@ inline bool IsVideo( DXGI_FORMAT fmt ) } } +_Use_decl_annotations_ +inline bool IsDepthStencil( DXGI_FORMAT fmt ) +{ + switch( static_cast(fmt) ) + { + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + case DXGI_FORMAT_D16_UNORM: + case 118 /* DXGI_FORMAT_D16_UNORM_S8_UINT */: + case 119 /* DXGI_FORMAT_R16_UNORM_X8_TYPELESS */: + case 120 /* DXGI_FORMAT_X16_TYPELESS_G8_UINT */: + return true; + + default: + return false; + } +} + _Use_decl_annotations_ inline bool IsSRGB( DXGI_FORMAT fmt ) { @@ -120,7 +191,7 @@ inline bool IsSRGB( DXGI_FORMAT fmt ) _Use_decl_annotations_ inline bool IsTypeless( DXGI_FORMAT fmt, bool partialTypeless ) { - switch( fmt ) + switch( static_cast(fmt) ) { case DXGI_FORMAT_R32G32B32A32_TYPELESS: case DXGI_FORMAT_R32G32B32_TYPELESS: @@ -152,6 +223,11 @@ inline bool IsTypeless( DXGI_FORMAT fmt, bool partialTypeless ) case DXGI_FORMAT_X24_TYPELESS_G8_UINT: return partialTypeless; + case 119 /* DXGI_FORMAT_R16_UNORM_X8_TYPELESS */: + case 120 /* DXGI_FORMAT_X16_TYPELESS_G8_UINT */: + // These are Xbox One platform specific types + return partialTypeless; + default: return false; } @@ -160,7 +236,7 @@ inline bool IsTypeless( DXGI_FORMAT fmt, bool partialTypeless ) _Use_decl_annotations_ inline bool HasAlpha( DXGI_FORMAT fmt ) { - switch( fmt ) + switch( static_cast(fmt) ) { case DXGI_FORMAT_R32G32B32A32_TYPELESS: case DXGI_FORMAT_R32G32B32A32_FLOAT: @@ -199,9 +275,20 @@ inline bool HasAlpha( DXGI_FORMAT fmt ) case DXGI_FORMAT_BC7_TYPELESS: case DXGI_FORMAT_BC7_UNORM: case DXGI_FORMAT_BC7_UNORM_SRGB: + case DXGI_FORMAT_AYUV: + case DXGI_FORMAT_Y410: + case DXGI_FORMAT_Y416: + case DXGI_FORMAT_AI44: + case DXGI_FORMAT_IA44: + case DXGI_FORMAT_A8P8: case DXGI_FORMAT_B4G4R4A4_UNORM: return true; + case 116 /* DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT */: + case 117 /* DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT */: + // These are Xbox One platform specific types + return true; + default: return false; } @@ -210,32 +297,21 @@ inline bool HasAlpha( DXGI_FORMAT fmt ) _Use_decl_annotations_ inline size_t ComputeScanlines( DXGI_FORMAT fmt, size_t height ) { - switch ( fmt ) + if ( IsCompressed(fmt) ) { - case DXGI_FORMAT_BC1_TYPELESS: - case DXGI_FORMAT_BC1_UNORM: - case DXGI_FORMAT_BC1_UNORM_SRGB: - case DXGI_FORMAT_BC2_TYPELESS: - case DXGI_FORMAT_BC2_UNORM: - case DXGI_FORMAT_BC2_UNORM_SRGB: - case DXGI_FORMAT_BC3_TYPELESS: - case DXGI_FORMAT_BC3_UNORM: - case DXGI_FORMAT_BC3_UNORM_SRGB: - case DXGI_FORMAT_BC4_TYPELESS: - case DXGI_FORMAT_BC4_UNORM: - case DXGI_FORMAT_BC4_SNORM: - case DXGI_FORMAT_BC5_TYPELESS: - case DXGI_FORMAT_BC5_UNORM: - case DXGI_FORMAT_BC5_SNORM: - case DXGI_FORMAT_BC6H_TYPELESS: - case DXGI_FORMAT_BC6H_UF16: - case DXGI_FORMAT_BC6H_SF16: - case DXGI_FORMAT_BC7_TYPELESS: - case DXGI_FORMAT_BC7_UNORM: - case DXGI_FORMAT_BC7_UNORM_SRGB: return std::max( 1, (height + 3) / 4 ); - - default: + } + else if ( fmt == DXGI_FORMAT_NV11 ) + { + // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data + return height * 2; + } + else if ( IsPlanar(fmt) ) + { + return height + ( ( height + 1 ) >> 1 ); + } + else + { return height; } } diff --git a/DirectXTex/DirectXTexCompress.cpp b/DirectXTex/DirectXTexCompress.cpp index 328e6b3..a66bbdf 100644 --- a/DirectXTex/DirectXTexCompress.cpp +++ b/DirectXTex/DirectXTexCompress.cpp @@ -147,6 +147,7 @@ static HRESULT _CompressBC( _In_ const Image& image, _In_ const Image& result, _ { for( size_t s = pw; s < 4; ++s ) { +#pragma prefast(suppress: 26000, "PREFAST false positive") temp[ (t << 2) | s ] = temp[ (t << 2) | uSrc[s] ]; } } @@ -158,6 +159,7 @@ static HRESULT _CompressBC( _In_ const Image& image, _In_ const Image& result, _ { for( size_t s = 0; s < 4; ++s ) { +#pragma prefast(suppress: 26000, "PREFAST false positive") temp[ (t << 2) | s ] = temp[ (uSrc[t] << 2) | s ]; } } @@ -561,9 +563,13 @@ bool _IsAlphaAllOpaqueBC( _In_ const Image& cImage ) _Use_decl_annotations_ HRESULT Compress( const Image& srcImage, DXGI_FORMAT format, DWORD compress, float alphaRef, ScratchImage& image ) { - if ( IsCompressed(srcImage.format) || !IsCompressed(format) || IsTypeless(format) ) + if ( IsCompressed(srcImage.format) || !IsCompressed(format) ) return E_INVALIDARG; + if ( IsTypeless(format) + || IsTypeless(srcImage.format) || IsPlanar(srcImage.format) || IsPalettized(srcImage.format) ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + // Create compressed image HRESULT hr = image.Initialize2D( format, srcImage.width, srcImage.height, 1, 1 ); if ( FAILED(hr) ) @@ -603,9 +609,13 @@ HRESULT Compress( const Image* srcImages, size_t nimages, const TexMetadata& met if ( !srcImages || !nimages ) return E_INVALIDARG; - if ( !IsCompressed(format) || IsTypeless(format) ) + if ( IsCompressed(metadata.format) || !IsCompressed(format) ) return E_INVALIDARG; + if ( IsTypeless(format) + || IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format) ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + cImages.Release(); TexMetadata mdata2 = metadata; @@ -676,7 +686,7 @@ HRESULT Compress( const Image* srcImages, size_t nimages, const TexMetadata& met _Use_decl_annotations_ HRESULT Decompress( const Image& cImage, DXGI_FORMAT format, ScratchImage& image ) { - if ( IsCompressed(format) || IsTypeless(format) ) + if ( !IsCompressed(cImage.format) || IsCompressed(format) ) return E_INVALIDARG; if ( format == DXGI_FORMAT_UNKNOWN ) @@ -689,8 +699,14 @@ HRESULT Decompress( const Image& cImage, DXGI_FORMAT format, ScratchImage& image return E_INVALIDARG; } } - else if ( !IsCompressed(cImage.format) || !IsValid(format) ) - return E_INVALIDARG; + else + { + if ( !IsValid(format) ) + return E_INVALIDARG; + + if ( IsTypeless(format) || IsPlanar(format) || IsPalettized(format) ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + } // Create decompressed image HRESULT hr = image.Initialize2D( format, cImage.width, cImage.height, 1, 1 ); @@ -719,7 +735,7 @@ HRESULT Decompress( const Image* cImages, size_t nimages, const TexMetadata& met if ( !cImages || !nimages ) return E_INVALIDARG; - if ( IsCompressed(format) || IsTypeless(format) ) + if ( !IsCompressed(metadata.format) || IsCompressed(format) ) return E_INVALIDARG; if ( format == DXGI_FORMAT_UNKNOWN ) @@ -732,8 +748,14 @@ HRESULT Decompress( const Image* cImages, size_t nimages, const TexMetadata& met return E_FAIL; } } - else if ( !IsValid(format) ) - return E_INVALIDARG; + else + { + if ( !IsValid(format) ) + return E_INVALIDARG; + + if ( IsTypeless(format) || IsPlanar(format) || IsPalettized(format) ) + HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + } images.Release(); diff --git a/DirectXTex/DirectXTexCompressGPU.cpp b/DirectXTex/DirectXTexCompressGPU.cpp index 921e3a6..dde80b5 100644 --- a/DirectXTex/DirectXTexCompressGPU.cpp +++ b/DirectXTex/DirectXTexCompressGPU.cpp @@ -200,9 +200,13 @@ inline static HRESULT _GPUCompress( _In_ GPUCompressBC* gpubc, _In_ const Image& _Use_decl_annotations_ HRESULT Compress( ID3D11Device* pDevice, const Image& srcImage, DXGI_FORMAT format, DWORD compress, ScratchImage& image ) { - if ( !pDevice || IsCompressed(srcImage.format) || !IsCompressed(format) || IsTypeless(format) ) + if ( !pDevice || IsCompressed(srcImage.format) || !IsCompressed(format) ) return E_INVALIDARG; + if ( IsTypeless(format) + || IsTypeless(srcImage.format) || IsPlanar(srcImage.format) || IsPalettized(srcImage.format) ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + // Setup GPU compressor std::unique_ptr gpubc( new (std::nothrow) GPUCompressBC ); if ( !gpubc ) @@ -242,9 +246,13 @@ HRESULT Compress( ID3D11Device* pDevice, const Image* srcImages, size_t nimages, if ( !pDevice || !srcImages || !nimages ) return E_INVALIDARG; - if ( !IsCompressed(format) || IsTypeless(format) ) + if ( IsCompressed(metadata.format) || !IsCompressed(format) ) return E_INVALIDARG; + if ( IsTypeless(format) + || IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format) ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + cImages.Release(); // Setup GPU compressor diff --git a/DirectXTex/DirectXTexConvert.cpp b/DirectXTex/DirectXTexConvert.cpp index 061c0a6..5fc33b0 100644 --- a/DirectXTex/DirectXTexConvert.cpp +++ b/DirectXTex/DirectXTexConvert.cpp @@ -18,9 +18,9 @@ using namespace DirectX::PackedVector; using Microsoft::WRL::ComPtr; -#if DIRECTX_MATH_VERSION < 306 namespace { +#if DIRECTX_MATH_VERSION < 306 inline float round_to_nearest( float x ) { // Round to nearest (even) @@ -40,9 +40,141 @@ namespace return i + 1.f; } -}; #endif + inline uint32_t FloatTo7e3(float Value) + { + uint32_t IValue = reinterpret_cast(&Value)[0]; + + if ( IValue & 0x80000000U ) + { + // Positive only + return 0; + } + else if (IValue > 0x41FF73FFU) + { + // The number is too large to be represented as a 7e3. Saturate. + return 0x3FFU; + } + else + { + if (IValue < 0x3E800000U) + { + // The number is too small to be represented as a normalized 7e3. + // Convert it to a denormalized value. + uint32_t Shift = 125U - (IValue >> 23U); + IValue = (0x800000U | (IValue & 0x7FFFFFU)) >> Shift; + } + else + { + // Rebias the exponent to represent the value as a normalized 7e3. + IValue += 0xC2000000U; + } + + return ((IValue + 0x7FFFU + ((IValue >> 16U) & 1U)) >> 16U)&0x3FFU; + } + } + + inline float FloatFrom7e3( uint32_t Value ) + { + uint32_t Mantissa = (uint32_t)(Value & 0x7F); + + uint32_t Exponent = (Value & 0x380); + if (Exponent != 0) // The value is normalized + { + Exponent = (uint32_t)((Value >> 7) & 0x7); + } + else if (Mantissa != 0) // The value is denormalized + { + // Normalize the value in the resulting float + Exponent = 1; + + do + { + Exponent--; + Mantissa <<= 1; + } while ((Mantissa & 0x80) == 0); + + Mantissa &= 0x7F; + } + else // The value is zero + { + Exponent = (uint32_t)-124; + } + + uint32_t Result = ((Exponent + 124) << 23) | // Exponent + (Mantissa << 16); // Mantissa + + return reinterpret_cast(&Result)[0]; + } + + inline uint32_t FloatTo6e4(float Value) + { + uint32_t IValue = reinterpret_cast(&Value)[0]; + + if ( IValue & 0x80000000U ) + { + // Positive only + return 0; + } + else if (IValue > 0x43FEFFFFU) + { + // The number is too large to be represented as a 6e4. Saturate. + return 0x3FFU; + } + else + { + if (IValue < 0x3C800000U) + { + // The number is too small to be represented as a normalized 6e4. + // Convert it to a denormalized value. + uint32_t Shift = 121U - (IValue >> 23U); + IValue = (0x800000U | (IValue & 0x7FFFFFU)) >> Shift; + } + else + { + // Rebias the exponent to represent the value as a normalized 6e4. + IValue += 0xC4000000U; + } + + return ((IValue + 0xFFFFU + ((IValue >> 17U) & 1U)) >> 17U)&0x3FFU; + } + } + + inline float FloatFrom6e4( uint32_t Value ) + { + uint32_t Mantissa = (uint32_t)(Value & 0x3F); + + uint32_t Exponent = (Value & 0x3C0); + if (Exponent != 0) // The value is normalized + { + Exponent = (uint32_t)((Value >> 6) & 0xF); + } + else if (Mantissa != 0) // The value is denormalized + { + // Normalize the value in the resulting float + Exponent = 1; + + do + { + Exponent--; + Mantissa <<= 1; + } while ((Mantissa & 0x40) == 0); + + Mantissa &= 0x3F; + } + else // The value is zero + { + Exponent = (uint32_t)-120; + } + + uint32_t Result = ((Exponent + 120) << 23) | // Exponent + (Mantissa << 17); // Mantissa + + return reinterpret_cast(&Result)[0]; + } +}; + namespace DirectX { static const XMVECTORF32 g_Grayscale = { 0.2125f, 0.7154f, 0.0721f, 0.0f }; @@ -59,11 +191,11 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize { assert( pDestination && outSize > 0 ); assert( pSource && inSize > 0 ); - assert( IsValid(format) && !IsVideo(format) ); + assert( IsValid(format) && !IsPalettized(format) ); if ( flags & TEXP_SCANLINE_SETALPHA ) { - switch( format ) + switch( static_cast(format) ) { //----------------------------------------------------------------------------- case DXGI_FORMAT_R32G32B32A32_TYPELESS: @@ -113,6 +245,7 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize case DXGI_FORMAT_R16G16B16A16_UINT: case DXGI_FORMAT_R16G16B16A16_SNORM: case DXGI_FORMAT_R16G16B16A16_SINT: + case DXGI_FORMAT_Y416: if ( inSize >= 8 && outSize >= 8 ) { uint16_t alpha; @@ -154,6 +287,9 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize case DXGI_FORMAT_R10G10B10A2_UNORM: case DXGI_FORMAT_R10G10B10A2_UINT: case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + case DXGI_FORMAT_Y410: + case 116 /* DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT */: + case 117 /* DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT */: if ( inSize >= 4 && outSize >= 4 ) { if ( pDestination == pSource ) @@ -188,6 +324,7 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize case DXGI_FORMAT_B8G8R8A8_UNORM: case DXGI_FORMAT_B8G8R8A8_TYPELESS: case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_AYUV: if ( inSize >= 4 && outSize >= 4 ) { const uint32_t alpha = ( format == DXGI_FORMAT_R8G8B8A8_SNORM || format == DXGI_FORMAT_R8G8B8A8_SINT ) ? 0x7f000000 : 0xff000000; @@ -292,7 +429,7 @@ void _SwizzleScanline( LPVOID pDestination, size_t outSize, LPCVOID pSource, siz { assert( pDestination && outSize > 0 ); assert( pSource && inSize > 0 ); - assert( IsValid(format) && !IsVideo(format) ); + assert( IsValid(format) && !IsPlanar(format) && !IsPalettized(format) ); switch( format ) { @@ -338,9 +475,10 @@ void _SwizzleScanline( LPVOID pDestination, size_t outSize, LPCVOID pSource, siz *(dPtr++) = t1 | t2 | t3 | ta; } } + return; } } - return; + break; //--------------------------------------------------------------------------------- case DXGI_FORMAT_R8G8B8A8_TYPELESS: @@ -387,8 +525,53 @@ void _SwizzleScanline( LPVOID pDestination, size_t outSize, LPCVOID pSource, siz *(dPtr++) = t1 | t2 | t3 | ta; } } + return; } - return; + break; + + //--------------------------------------------------------------------------------- + case DXGI_FORMAT_YUY2: + if ( inSize >= 4 && outSize >= 4 ) + { + if ( flags & TEXP_SCANLINE_LEGACY ) + { + // Reorder YUV components (used to convert legacy UYVY -> YUY2) + if ( pDestination == pSource ) + { + uint32_t *dPtr = reinterpret_cast(pDestination); + for( size_t count = 0; count < ( outSize - 3 ); count += 4 ) + { + uint32_t t = *dPtr; + + uint32_t t1 = (t & 0x000000ff) << 8; + uint32_t t2 = (t & 0x0000ff00) >> 8; + uint32_t t3 = (t & 0x00ff0000) << 8; + uint32_t t4 = (t & 0xff000000) >> 8; + + *(dPtr++) = t1 | t2 | t3 | t4; + } + } + else + { + const uint32_t * __restrict sPtr = reinterpret_cast(pSource); + uint32_t * __restrict dPtr = reinterpret_cast(pDestination); + size_t size = std::min( outSize, inSize ); + for( size_t count = 0; count < ( size - 3 ); count += 4 ) + { + uint32_t t = *(sPtr++); + + uint32_t t1 = (t & 0x000000ff) << 8; + uint32_t t2 = (t & 0x0000ff00) >> 8; + uint32_t t3 = (t & 0x00ff0000) << 8; + uint32_t t4 = (t & 0xff000000) >> 8; + + *(dPtr++) = t1 | t2 | t3 | t4; + } + } + return; + } + } + break; } // Fall-through case is to just use memcpy (assuming this is not an in-place operation) @@ -410,8 +593,8 @@ bool _ExpandScanline( LPVOID pDestination, size_t outSize, DXGI_FORMAT outFormat { assert( pDestination && outSize > 0 ); assert( pSource && inSize > 0 ); - assert( IsValid(outFormat) && !IsVideo(outFormat) ); - assert( IsValid(inFormat) && !IsVideo(inFormat) ); + assert( IsValid(outFormat) && !IsPlanar(outFormat) && !IsPalettized(outFormat) ); + assert( IsValid(inFormat) && !IsPlanar(inFormat) && !IsPalettized(inFormat) ); switch( inFormat ) { @@ -544,7 +727,7 @@ bool _LoadScanline( XMVECTOR* pDestination, size_t count, { assert( pDestination && count > 0 && (((uintptr_t)pDestination & 0xF) == 0) ); assert( pSource && size > 0 ); - assert( IsValid(format) && !IsVideo(format) && !IsTypeless(format, false) && !IsCompressed(format) ); + assert( IsValid(format) && !IsTypeless(format, false) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format) ); XMVECTOR* __restrict dPtr = pDestination; if ( !dPtr ) @@ -552,7 +735,7 @@ bool _LoadScanline( XMVECTOR* pDestination, size_t count, const XMVECTOR* ePtr = pDestination + count; - switch( format ) + switch( static_cast(format) ) { case DXGI_FORMAT_R32G32B32A32_FLOAT: { @@ -1099,6 +1282,226 @@ bool _LoadScanline( XMVECTOR* pDestination, size_t count, } return false; + case DXGI_FORMAT_AYUV: + if ( size >= sizeof(XMUBYTEN4) ) + { + const XMUBYTEN4 * __restrict sPtr = reinterpret_cast(pSource); + for( size_t icount = 0; icount < ( size - sizeof(XMUBYTEN4) + 1 ); icount += sizeof(XMUBYTEN4) ) + { + int v = int(sPtr->x) - 128; + int u = int(sPtr->y) - 128; + int y = int(sPtr->z) - 16; + unsigned int a = sPtr->w; + ++sPtr; + + // http://msdn.microsoft.com/en-us/library/windows/desktop/dd206750.aspx + + // Y’ = Y - 16 + // Cb’ = Cb - 128 + // Cr’ = Cr - 128 + + // R = 1.1644Y’ + 1.5960Cr’ + // G = 1.1644Y’ - 0.3917Cb’ - 0.8128Cr’ + // B = 1.1644Y’ + 2.0172Cb’ + + int r = (298 * y + 409 * v + 128) >> 8; + int g = (298 * y - 100 * u - 208 * v + 128) >> 8; + int b = (298 * y + 516 * u + 128) >> 8; + + if ( dPtr >= ePtr ) break; + *(dPtr++) = XMVectorSet( float( std::min( std::max( r, 0 ), 255 ) ) / 255.f, + float( std::min( std::max( g, 0 ), 255 ) ) / 255.f, + float( std::min( std::max( b, 0 ), 255 ) ) / 255.f, + float( a / 255.f ) ); + } + return true; + } + return false; + + case DXGI_FORMAT_Y410: + if ( size >= sizeof(XMUDECN4) ) + { + const XMUDECN4 * __restrict sPtr = reinterpret_cast(pSource); + for( size_t icount = 0; icount < ( size - sizeof(XMUDECN4) + 1 ); icount += sizeof(XMUDECN4) ) + { + int64_t u = int(sPtr->x) - 512; + int64_t y = int(sPtr->y) - 64; + int64_t v = int(sPtr->z) - 512; + unsigned int a = sPtr->w; + ++sPtr; + + // http://msdn.microsoft.com/en-us/library/windows/desktop/bb970578.aspx + + // Y’ = Y - 64 + // Cb’ = Cb - 512 + // Cr’ = Cr - 512 + + // R = 1.1678Y’ + 1.6007Cr’ + // G = 1.1678Y’ - 0.3929Cb’ - 0.8152Cr’ + // B = 1.1678Y’ + 2.0232Cb’ + + int r = static_cast( (76533 * y + 104905 * v + 32768) >> 16 ); + int g = static_cast( (76533 * y - 25747 * u - 53425 * v + 32768) >> 16 ); + int b = static_cast( (76533 * y + 132590 * u + 32768) >> 16 ); + + if ( dPtr >= ePtr ) break; + *(dPtr++) = XMVectorSet( float( std::min( std::max( r, 0 ), 1023 ) ) / 1023.f, + float( std::min( std::max( g, 0 ), 1023 ) ) / 1023.f, + float( std::min( std::max( b, 0 ), 1023 ) ) / 1023.f, + float( a / 3.f ) ); + } + return true; + } + return false; + + case DXGI_FORMAT_Y416: + if ( size >= sizeof(XMUSHORTN4) ) + { + const XMUSHORTN4 * __restrict sPtr = reinterpret_cast(pSource); + for( size_t icount = 0; icount < ( size - sizeof(XMUSHORTN4) + 1 ); icount += sizeof(XMUSHORTN4) ) + { + int64_t u = int64_t(sPtr->x) - 32768; + int64_t y = int64_t(sPtr->y) - 4096; + int64_t v = int64_t(sPtr->z) - 32768; + unsigned int a = sPtr->w; + ++sPtr; + + // http://msdn.microsoft.com/en-us/library/windows/desktop/bb970578.aspx + + // Y’ = Y - 4096 + // Cb’ = Cb - 32768 + // Cr’ = Cr - 32768 + + // R = 1.1689Y’ + 1.6023Cr’ + // G = 1.1689Y’ - 0.3933Cb’ - 0.8160Cr’ + // B = 1.1689Y’+ 2.0251Cb’ + + int r = static_cast( (76607 * y + 105006 * v + 32768) >> 16 ); + int g = static_cast( (76607 * y - 25772 * u - 53477 * v + 32768) >> 16 ); + int b = static_cast( (76607 * y + 132718 * u + 32768) >> 16 ); + + if ( dPtr >= ePtr ) break; + *(dPtr++) = XMVectorSet( float( std::min( std::max( r, 0 ), 65535 ) ) / 65535.f, + float( std::min( std::max( g, 0 ), 65535 ) ) / 65535.f, + float( std::min( std::max( b, 0 ), 65535 ) ) / 65535.f, + float( std::min( std::max( a, 0 ), 65535 ) ) / 65535.f ); + } + return true; + } + return false; + + case DXGI_FORMAT_YUY2: + if ( size >= sizeof(XMUBYTEN4) ) + { + const XMUBYTEN4 * __restrict sPtr = reinterpret_cast(pSource); + for( size_t icount = 0; icount < ( size - sizeof(XMUBYTEN4) + 1 ); icount += sizeof(XMUBYTEN4) ) + { + int y0 = int(sPtr->x) - 16; + int u = int(sPtr->y) - 128; + int y1 = int(sPtr->z) - 16; + int v = int(sPtr->w) - 128; + ++sPtr; + + // See AYUV + int r = (298 * y0 + 409 * v + 128) >> 8; + int g = (298 * y0 - 100 * u - 208 * v + 128) >> 8; + int b = (298 * y0 + 516 * u + 128) >> 8; + + if ( dPtr >= ePtr ) break; + *(dPtr++) = XMVectorSet( float( std::min( std::max( r, 0 ), 255 ) ) / 255.f, + float( std::min( std::max( g, 0 ), 255 ) ) / 255.f, + float( std::min( std::max( b, 0 ), 255 ) ) / 255.f, + 1.f ); + + r = (298 * y1 + 409 * v + 128) >> 8; + g = (298 * y1 - 100 * u - 208 * v + 128) >> 8; + b = (298 * y1 + 516 * u + 128) >> 8; + + if ( dPtr >= ePtr ) break; + *(dPtr++) = XMVectorSet( float( std::min( std::max( r, 0 ), 255 ) ) / 255.f, + float( std::min( std::max( g, 0 ), 255 ) ) / 255.f, + float( std::min( std::max( b, 0 ), 255 ) ) / 255.f, + 1.f ); + } + return true; + } + return false; + + case DXGI_FORMAT_Y210: + // Same as Y216 with least significant 6 bits set to zero + if ( size >= sizeof(XMUSHORTN4) ) + { + const XMUSHORTN4 * __restrict sPtr = reinterpret_cast(pSource); + for( size_t icount = 0; icount < ( size - sizeof(XMUSHORTN4) + 1 ); icount += sizeof(XMUSHORTN4) ) + { + int64_t y0 = int64_t(sPtr->x >> 6) - 64; + int64_t u = int64_t(sPtr->y >> 6) - 512; + int64_t y1 = int64_t(sPtr->z >> 6) - 64; + int64_t v = int64_t(sPtr->w >> 6) - 512; + ++sPtr; + + // See Y410 + int r = static_cast( (76533 * y0 + 104905 * v + 32768) >> 16 ); + int g = static_cast( (76533 * y0 - 25747 * u - 53425 * v + 32768) >> 16 ); + int b = static_cast( (76533 * y0 + 132590 * u + 32768) >> 16 ); + + if ( dPtr >= ePtr ) break; + *(dPtr++) = XMVectorSet( float( std::min( std::max( r, 0 ), 1023 ) ) / 1023.f, + float( std::min( std::max( g, 0 ), 1023 ) ) / 1023.f, + float( std::min( std::max( b, 0 ), 1023 ) ) / 1023.f, + 1.f ); + + r = static_cast( (76533 * y1 + 104905 * v + 32768) >> 16 ); + g = static_cast( (76533 * y1 - 25747 * u - 53425 * v + 32768) >> 16 ); + b = static_cast( (76533 * y1 + 132590 * u + 32768) >> 16 ); + + if ( dPtr >= ePtr ) break; + *(dPtr++) = XMVectorSet( float( std::min( std::max( r, 0 ), 1023 ) ) / 1023.f, + float( std::min( std::max( g, 0 ), 1023 ) ) / 1023.f, + float( std::min( std::max( b, 0 ), 1023 ) ) / 1023.f, + 1.f ); + } + return true; + } + return false; + + case DXGI_FORMAT_Y216: + if ( size >= sizeof(XMUSHORTN4) ) + { + const XMUSHORTN4 * __restrict sPtr = reinterpret_cast(pSource); + for( size_t icount = 0; icount < ( size - sizeof(XMUSHORTN4) + 1 ); icount += sizeof(XMUSHORTN4) ) + { + int64_t y0 = int64_t(sPtr->x) - 4096; + int64_t u = int64_t(sPtr->y) - 32768; + int64_t y1 = int64_t(sPtr->z) - 4096; + int64_t v = int64_t(sPtr->w) - 32768; + ++sPtr; + + // See Y416 + int r = static_cast( (76607 * y0 + 105006 * v + 32768) >> 16 ); + int g = static_cast( (76607 * y0 - 25772 * u - 53477 * v + 32768) >> 16 ); + int b = static_cast( (76607 * y0 + 132718 * u + 32768) >> 16 ); + + if ( dPtr >= ePtr ) break; + *(dPtr++) = XMVectorSet( float( std::min( std::max( r, 0 ), 65535 ) ) / 65535.f, + float( std::min( std::max( g, 0 ), 65535 ) ) / 65535.f, + float( std::min( std::max( b, 0 ), 65535 ) ) / 65535.f, + 1.f ); + + r = static_cast( (76607 * y1 + 105006 * v + 32768) >> 16 ); + g = static_cast( (76607 * y1 - 25772 * u - 53477 * v + 32768) >> 16 ); + b = static_cast( (76607 * y1 + 132718 * u + 32768) >> 16 ); + + if ( dPtr >= ePtr ) break; + *(dPtr++) = XMVectorSet( float( std::min( std::max( r, 0 ), 65535 ) ) / 65535.f, + float( std::min( std::max( g, 0 ), 65535 ) ) / 65535.f, + float( std::min( std::max( b, 0 ), 65535 ) ) / 65535.f, + 1.f ); + } + return true; + } + return false; + case DXGI_FORMAT_B4G4R4A4_UNORM: if ( size >= sizeof(XMUNIBBLE4) ) { @@ -1115,7 +1518,55 @@ bool _LoadScanline( XMVECTOR* pDestination, size_t count, } return false; - // we don't support the video formats ( see IsVideo function ) + case 116 /* DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT */: + // Xbox One specific 7e3 format + if ( size >= sizeof(XMUDECN4) ) + { + const XMUDECN4 * __restrict sPtr = reinterpret_cast(pSource); + for( size_t icount = 0; icount < ( size - sizeof(XMUDECN4) + 1 ); icount += sizeof(XMUDECN4) ) + { + if ( dPtr >= ePtr ) break; + + XMVECTORF32 vResult = { + FloatFrom7e3(sPtr->x), + FloatFrom7e3(sPtr->y), + FloatFrom7e3(sPtr->z), + (float)(sPtr->v >> 30) / 3.0f + }; + + ++sPtr; + + *(dPtr++) = vResult.v; + } + return true; + } + return false; + + case 117 /* DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT */: + // Xbox One specific 6e4 format + if ( size >= sizeof(XMUDECN4) ) + { + const XMUDECN4 * __restrict sPtr = reinterpret_cast(pSource); + for( size_t icount = 0; icount < ( size - sizeof(XMUDECN4) + 1 ); icount += sizeof(XMUDECN4) ) + { + if ( dPtr >= ePtr ) break; + + XMVECTORF32 vResult = { + FloatFrom6e4(sPtr->x), + FloatFrom6e4(sPtr->y), + FloatFrom6e4(sPtr->z), + (float)(sPtr->v >> 30) / 3.0f + }; + + ++sPtr; + + *(dPtr++) = vResult.v; + } + return true; + } + return false; + + // We don't support the planar or palettized formats default: return false; @@ -1149,7 +1600,7 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, { assert( pDestination && size > 0 ); assert( pSource && count > 0 && (((uintptr_t)pSource & 0xF) == 0) ); - assert( IsValid(format) && !IsVideo(format) && !IsTypeless(format) && !IsCompressed(format) ); + assert( IsValid(format) && !IsTypeless(format) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format) ); const XMVECTOR* __restrict sPtr = pSource; if ( !sPtr ) @@ -1157,7 +1608,7 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, const XMVECTOR* ePtr = pSource + count; - switch( format ) + switch( static_cast(format) ) { case DXGI_FORMAT_R32G32B32A32_FLOAT: STORE_SCANLINE( XMFLOAT4, XMStoreFloat4 ) @@ -1681,6 +2132,244 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, } return false; + case DXGI_FORMAT_AYUV: + if ( size >= sizeof(XMUBYTEN4) ) + { + XMUBYTEN4 * __restrict dPtr = reinterpret_cast(pDestination); + for( size_t icount = 0; icount < ( size - sizeof(XMUBYTEN4) + 1 ); icount += sizeof(XMUBYTEN4) ) + { + if ( sPtr >= ePtr ) break; + + XMUBYTEN4 rgba; + XMStoreUByteN4( &rgba, *sPtr++ ); + + // http://msdn.microsoft.com/en-us/library/windows/desktop/dd206750.aspx + + // Y = 0.2568R + 0.5041G + 0.1001B + 16 + // Cb = -0.1482R - 0.2910G + 0.4392B + 128 + // Cr = 0.4392R - 0.3678G - 0.0714B + 128 + + int y = ( ( 66 * rgba.x + 129 * rgba.y + 25 * rgba.z + 128) >> 8) + 16; + int u = ( ( -38 * rgba.x - 74 * rgba.y + 112 * rgba.z + 128) >> 8) + 128; + int v = ( ( 112 * rgba.x - 94 * rgba.y - 18 * rgba.z + 128) >> 8) + 128; + + dPtr->x = static_cast( std::min( std::max( v, 0 ), 255 ) ); + dPtr->y = static_cast( std::min( std::max( u, 0 ), 255 ) ); + dPtr->z = static_cast( std::min( std::max( y, 0 ), 255 ) ); + dPtr->w = rgba.w; + ++dPtr; + } + return true; + } + return false; + + case DXGI_FORMAT_Y410: + if ( size >= sizeof(XMUDECN4) ) + { + XMUDECN4 * __restrict dPtr = reinterpret_cast(pDestination); + for( size_t icount = 0; icount < ( size - sizeof(XMUDECN4) + 1 ); icount += sizeof(XMUDECN4) ) + { + if ( sPtr >= ePtr ) break; + + XMUDECN4 rgba; + XMStoreUDecN4( &rgba, *sPtr++ ); + + // http://msdn.microsoft.com/en-us/library/windows/desktop/bb970578.aspx + + // Y = 0.2560R + 0.5027G + 0.0998B + 64 + // Cb = -0.1478R - 0.2902G + 0.4379B + 512 + // Cr = 0.4379R - 0.3667G - 0.0712B + 512 + + int64_t r = rgba.x; + int64_t g = rgba.y; + int64_t b = rgba.z; + + int y = static_cast( ( 16780 * r + 32942 * g + 6544 * b + 32768) >> 16) + 64; + int u = static_cast( ( -9683 * r - 19017 * g + 28700 * b + 32768) >> 16) + 512; + int v = static_cast( ( 28700 * r - 24033 * g - 4667 * b + 32768) >> 16) + 512; + + dPtr->x = static_cast( std::min( std::max( u, 0 ), 1023 ) ); + dPtr->y = static_cast( std::min( std::max( y, 0 ), 1023 ) ); + dPtr->z = static_cast( std::min( std::max( v, 0 ), 1023 ) ); + dPtr->w = rgba.w; + ++dPtr; + } + return true; + } + return false; + + case DXGI_FORMAT_Y416: + if ( size >= sizeof(XMUSHORTN4) ) + { + XMUSHORTN4 * __restrict dPtr = reinterpret_cast(pDestination); + for( size_t icount = 0; icount < ( size - sizeof(XMUSHORTN4) + 1 ); icount += sizeof(XMUSHORTN4) ) + { + if ( sPtr >= ePtr ) break; + + XMUSHORTN4 rgba; + XMStoreUShortN4( &rgba, *sPtr++ ); + + // http://msdn.microsoft.com/en-us/library/windows/desktop/bb970578.aspx + + // Y = 0.2558R + 0.5022G + 0.0998B + 4096 + // Cb = -0.1476R - 0.2899G + 0.4375B + 32768 + // Cr = 0.4375R - 0.3664G - 0.0711B + 32768 + + int64_t r = int64_t(rgba.x); + int64_t g = int64_t(rgba.y); + int64_t b = int64_t(rgba.z); + + int y = static_cast( ( 16763 * r + 32910 * g + 6537 * b + 32768) >> 16) + 4096; + int u = static_cast( ( -9674 * r - 18998 * g + 28672 * b + 32768) >> 16) + 32768; + int v = static_cast( ( 28672 * r - 24010 * g - 4662 * b + 32768) >> 16) + 32768; + + dPtr->x = static_cast( std::min( std::max( u, 0 ), 65535 ) ); + dPtr->y = static_cast( std::min( std::max( y, 0 ), 65535 ) ); + dPtr->z = static_cast( std::min( std::max( v, 0 ), 65535 ) ); + dPtr->w = rgba.w; + ++dPtr; + } + return true; + } + return false; + + case DXGI_FORMAT_YUY2: + if ( size >= sizeof(XMUBYTEN4) ) + { + XMUBYTEN4 * __restrict dPtr = reinterpret_cast(pDestination); + for( size_t icount = 0; icount < ( size - sizeof(XMUBYTEN4) + 1 ); icount += sizeof(XMUBYTEN4) ) + { + if ( sPtr >= ePtr ) break; + + XMUBYTEN4 rgb1; + XMStoreUByteN4( &rgb1, *sPtr++ ); + + // See AYUV + int y0 = ( ( 66 * rgb1.x + 129 * rgb1.y + 25 * rgb1.z + 128) >> 8) + 16; + int u0 = ( ( -38 * rgb1.x - 74 * rgb1.y + 112 * rgb1.z + 128) >> 8) + 128; + int v0 = ( ( 112 * rgb1.x - 94 * rgb1.y - 18 * rgb1.z + 128) >> 8) + 128; + + XMUBYTEN4 rgb2; + if(sPtr < ePtr) + { + XMStoreUByteN4( &rgb2, *sPtr++ ); + } + else + { + rgb2.x = rgb2.y = rgb2.z = rgb2.w = 0; + } + + int y1 = ( ( 66 * rgb2.x + 129 * rgb2.y + 25 * rgb2.z + 128) >> 8) + 16; + int u1 = ( ( -38 * rgb2.x - 74 * rgb2.y + 112 * rgb2.z + 128) >> 8) + 128; + int v1 = ( ( 112 * rgb2.x - 94 * rgb2.y - 18 * rgb2.z + 128) >> 8) + 128; + + dPtr->x = static_cast( std::min( std::max( y0, 0 ), 255 ) ); + dPtr->y = static_cast( std::min( std::max( (u0 + u1) >> 1, 0 ), 255 ) ); + dPtr->z = static_cast( std::min( std::max( y1, 0 ), 255 ) ); + dPtr->w = static_cast( std::min( std::max( (v0 + v1) >> 1, 0 ), 255 ) ); + ++dPtr; + } + return true; + } + return false; + + case DXGI_FORMAT_Y210: + // Same as Y216 with least significant 6 bits set to zero + if ( size >= sizeof(XMUSHORTN4) ) + { + XMUSHORTN4 * __restrict dPtr = reinterpret_cast(pDestination); + for( size_t icount = 0; icount < ( size - sizeof(XMUSHORTN4) + 1 ); icount += sizeof(XMUSHORTN4) ) + { + if ( sPtr >= ePtr ) break; + + XMUDECN4 rgb1; + XMStoreUDecN4( &rgb1, *sPtr++ ); + + // See Y410 + int64_t r = rgb1.x; + int64_t g = rgb1.y; + int64_t b = rgb1.z; + + int y0 = static_cast( ( 16780 * r + 32942 * g + 6544 * b + 32768) >> 16) + 64; + int u0 = static_cast( ( -9683 * r - 19017 * g + 28700 * b + 32768) >> 16) + 512; + int v0 = static_cast( ( 28700 * r - 24033 * g - 4667 * b + 32768) >> 16) + 512; + + XMUDECN4 rgb2; + if(sPtr < ePtr) + { + XMStoreUDecN4( &rgb2, *sPtr++ ); + } + else + { + rgb2.x = rgb2.y = rgb2.z = rgb2.w = 0; + } + + r = rgb2.x; + g = rgb2.y; + b = rgb2.z; + + int y1 = static_cast( ( 16780 * r + 32942 * g + 6544 * b + 32768) >> 16) + 64; + int u1 = static_cast( ( -9683 * r - 19017 * g + 28700 * b + 32768) >> 16) + 512; + int v1 = static_cast( ( 28700 * r - 24033 * g - 4667 * b + 32768) >> 16) + 512; + + dPtr->x = static_cast( std::min( std::max( y0, 0 ), 1023 ) << 6 ); + dPtr->y = static_cast( std::min( std::max( (u0 + u1) >> 1, 0 ), 1023 ) << 6 ); + dPtr->z = static_cast( std::min( std::max( y1, 0 ), 1023 ) << 6 ); + dPtr->w = static_cast( std::min( std::max( (v0 + v1) >> 1, 0 ), 1023 ) << 6 ); + ++dPtr; + } + return true; + } + return false; + + case DXGI_FORMAT_Y216: + if ( size >= sizeof(XMUSHORTN4) ) + { + XMUSHORTN4 * __restrict dPtr = reinterpret_cast(pDestination); + for( size_t icount = 0; icount < ( size - sizeof(XMUSHORTN4) + 1 ); icount += sizeof(XMUSHORTN4) ) + { + if ( sPtr >= ePtr ) break; + + XMUSHORTN4 rgb1; + XMStoreUShortN4( &rgb1, *sPtr++ ); + + // See Y416 + int64_t r = int64_t(rgb1.x); + int64_t g = int64_t(rgb1.y); + int64_t b = int64_t(rgb1.z); + + int y0 = static_cast( ( 16763 * r + 32910 * g + 6537 * b + 32768) >> 16) + 4096; + int u0 = static_cast( (-9674 * r - 18998 * g + 28672 * b + 32768) >> 16) + 32768; + int v0 = static_cast( ( 28672 * r - 24010 * g - 4662 * b + 32768) >> 16) + 32768; + + XMUSHORTN4 rgb2; + if(sPtr < ePtr) + { + XMStoreUShortN4( &rgb2, *sPtr++ ); + } + else + { + rgb2.x = rgb2.y = rgb2.z = rgb2.w = 0; + } + + r = int64_t(rgb2.x); + g = int64_t(rgb2.y); + b = int64_t(rgb2.z); + + int y1 = static_cast( ( 16763 * r + 32910 * g + 6537 * b + 32768) >> 16) + 4096; + int u1 = static_cast( (-9674 * r - 18998 * g + 28672 * b + 32768) >> 16) + 32768; + int v1 = static_cast( ( 28672 * r - 24010 * g - 4662 * b + 32768) >> 16) + 32768; + + dPtr->x = static_cast( std::min( std::max( y0, 0 ), 65535 ) ); + dPtr->y = static_cast( std::min( std::max( (u0 + u1) >> 1, 0 ), 65535 ) ); + dPtr->z = static_cast( std::min( std::max( y1, 0 ), 65535 ) ); + dPtr->w = static_cast( std::min( std::max( (v0 + v1) >> 1, 0 ), 65535 ) ); + ++dPtr; + } + return true; + } + return false; + case DXGI_FORMAT_B4G4R4A4_UNORM: if ( size >= sizeof(XMUNIBBLE4) ) { @@ -1697,7 +2386,63 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, } return false; - // We don't support the video formats ( see IsVideo function ) + case 116 /* DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT */: + // Xbox One specific 7e3 format with alpha + if ( size >= sizeof(XMUDECN4) ) + { + static const XMVECTORF32 Scale = { 1.0f, 1.0f, 1.0f, 3.0f }; + static const XMVECTORF32 C = { 31.875f, 31.875f, 31.875f, 3.f }; + + XMUDECN4 * __restrict dPtr = reinterpret_cast(pDestination); + for( size_t icount = 0; icount < ( size - sizeof(XMUDECN4) + 1 ); icount += sizeof(XMUDECN4) ) + { + if ( sPtr >= ePtr ) break; + + XMVECTOR V = XMVectorMultiply( *sPtr++, Scale ); + V = XMVectorClamp( V, g_XMZero, C ); + + XMFLOAT4A tmp; + XMStoreFloat4A( &tmp, V ); + + dPtr->x = FloatTo7e3( tmp.x ); + dPtr->y = FloatTo7e3( tmp.y ); + dPtr->z = FloatTo7e3( tmp.z ); + dPtr->w = (uint32_t)tmp.w; + ++dPtr; + } + return true; + } + return false; + + case 117 /* DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT */: + // Xbox One specific 6e4 format with alpha + if ( size >= sizeof(XMUDECN4) ) + { + static const XMVECTORF32 Scale = { 1.0f, 1.0f, 1.0f, 3.0f }; + static const XMVECTORF32 C = { 508.f, 508.f, 508.f, 3.f }; + + XMUDECN4 * __restrict dPtr = reinterpret_cast(pDestination); + for( size_t icount = 0; icount < ( size - sizeof(XMUDECN4) + 1 ); icount += sizeof(XMUDECN4) ) + { + if ( sPtr >= ePtr ) break; + + XMVECTOR V = XMVectorMultiply( *sPtr++, Scale ); + V = XMVectorClamp( V, g_XMZero, C ); + + XMFLOAT4A tmp; + XMStoreFloat4A( &tmp, V ); + + dPtr->x = FloatTo6e4( tmp.x ); + dPtr->y = FloatTo6e4( tmp.y ); + dPtr->z = FloatTo6e4( tmp.z ); + dPtr->w = (uint32_t)tmp.w; + ++dPtr; + } + return true; + } + return false; + + // We don't support the planar or palettized formats default: return false; @@ -1902,7 +2647,7 @@ bool _StoreScanlineLinear( LPVOID pDestination, size_t size, DXGI_FORMAT format, { assert( pDestination && size > 0 ); assert( pSource && count > 0 && (((uintptr_t)pSource & 0xF) == 0) ); - assert( IsValid(format) && !IsVideo(format) && !IsTypeless(format) && !IsCompressed(format) ); + assert( IsValid(format) && !IsTypeless(format) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format) ); switch ( format ) { @@ -1990,7 +2735,7 @@ bool _LoadScanlineLinear( XMVECTOR* pDestination, size_t count, { assert( pDestination && count > 0 && (((uintptr_t)pDestination & 0xF) == 0) ); assert( pSource && size > 0 ); - assert( IsValid(format) && !IsVideo(format) && !IsTypeless(format,false) && !IsCompressed(format) ); + assert( IsValid(format) && !IsTypeless(format,false) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format) ); switch ( format ) { @@ -2134,7 +2879,17 @@ static const ConvertData g_ConvertTable[] = { { DXGI_FORMAT_BC6H_SF16, 16, CONVF_FLOAT | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, { DXGI_FORMAT_BC7_UNORM, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, { DXGI_FORMAT_BC7_UNORM_SRGB, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_AYUV, 8, CONVF_UNORM | CONVF_YUV | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_Y410, 10, CONVF_UNORM | CONVF_YUV | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_Y416, 16, CONVF_UNORM | CONVF_YUV | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_YUY2, 8, CONVF_UNORM | CONVF_YUV | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B }, + { DXGI_FORMAT_Y210, 10, CONVF_UNORM | CONVF_YUV | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B }, + { DXGI_FORMAT_Y216, 16, CONVF_UNORM | CONVF_YUV | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B }, { DXGI_FORMAT_B4G4R4A4_UNORM, 4, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT(116) + /* DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT */, 10, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT(117) + /* DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT */, 10, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, }; #pragma prefast( suppress : 25004, "Signature must match bsearch_s" ); @@ -2171,8 +2926,8 @@ _Use_decl_annotations_ void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, DXGI_FORMAT inFormat, DWORD flags ) { assert( pBuffer && count > 0 && (((uintptr_t)pBuffer & 0xF) == 0) ); - assert( IsValid(outFormat) && !IsVideo(outFormat) && !IsTypeless(outFormat) ); - assert( IsValid(inFormat) && !IsVideo(inFormat) && !IsTypeless(inFormat) ); + assert( IsValid(outFormat) && !IsTypeless(outFormat) && !IsPlanar(outFormat) && !IsPalettized(outFormat) ); + assert( IsValid(inFormat) && !IsTypeless(inFormat) && !IsPlanar(inFormat) && !IsPalettized(inFormat) ); if ( !pBuffer ) return; @@ -2651,7 +3406,7 @@ bool _StoreScanlineDither( LPVOID pDestination, size_t size, DXGI_FORMAT format, { assert( pDestination && size > 0 ); assert( pSource && count > 0 && (((uintptr_t)pSource & 0xF) == 0) ); - assert( IsValid(format) && !IsVideo(format) && !IsTypeless(format) && !IsCompressed(format) ); + assert( IsValid(format) && !IsTypeless(format) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format) ); XMVECTOR ordered[4]; if ( pDiffusionErrors ) @@ -3279,6 +4034,156 @@ static HRESULT _Convert( _In_ const Image& srcImage, _In_ DWORD filter, _In_ con } +//------------------------------------------------------------------------------------- +static DXGI_FORMAT _PlanarToSingle( _In_ DXGI_FORMAT format ) +{ + switch (format) + { + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_NV11: + return DXGI_FORMAT_YUY2; + + case DXGI_FORMAT_P010: + return DXGI_FORMAT_Y210; + + case DXGI_FORMAT_P016: + return DXGI_FORMAT_Y216; + + // We currently do not support conversion for Xbox One specific depth formats + + // We can't do anything with DXGI_FORMAT_420_OPAQUE because it's an opaque blob of bits + + default: + return DXGI_FORMAT_UNKNOWN; + } +} + + +//------------------------------------------------------------------------------------- +// Convert the image from a planar to non-planar image +//------------------------------------------------------------------------------------- +#define CONVERT_420_TO_422( srcType, destType )\ + {\ + size_t rowPitch = srcImage.rowPitch;\ + \ + auto sourceE = reinterpret_cast( pSrc + srcImage.slicePitch );\ + auto pSrcUV = pSrc + ( srcImage.height * rowPitch );\ + \ + for( size_t y = 0; y < srcImage.height; y+= 2 )\ + {\ + auto sPtrY0 = reinterpret_cast( pSrc );\ + auto sPtrY2 = reinterpret_cast( pSrc + rowPitch );\ + auto sPtrUV = reinterpret_cast( pSrcUV );\ + \ + destType * __restrict dPtr0 = reinterpret_cast(pDest);\ + destType * __restrict dPtr1 = reinterpret_cast(pDest + destImage.rowPitch);\ + \ + for( size_t x = 0; x < srcImage.width; x+= 2 )\ + {\ + if ( (sPtrUV+1) >= sourceE ) break;\ + \ + srcType u = *(sPtrUV++);\ + srcType v = *(sPtrUV++);\ + \ + dPtr0->x = *(sPtrY0++);\ + dPtr0->y = u;\ + dPtr0->z = *(sPtrY0++);\ + dPtr0->w = v;\ + ++dPtr0;\ + \ + dPtr1->x = *(sPtrY2++);\ + dPtr1->y = u;\ + dPtr1->z = *(sPtrY2++);\ + dPtr1->w = v;\ + ++dPtr1;\ + }\ + \ + pSrc += rowPitch * 2;\ + pSrcUV += rowPitch;\ + \ + pDest += destImage.rowPitch * 2;\ + }\ + } + +static HRESULT _ConvertToSinglePlane( _In_ const Image& srcImage, _In_ const Image& destImage ) +{ + assert( srcImage.width == destImage.width ); + assert( srcImage.height == destImage.height ); + + const uint8_t *pSrc = srcImage.pixels; + uint8_t *pDest = destImage.pixels; + if ( !pSrc || !pDest ) + return E_POINTER; + + switch ( srcImage.format ) + { + case DXGI_FORMAT_NV12: + assert( destImage.format == DXGI_FORMAT_YUY2 ); + CONVERT_420_TO_422( uint8_t, XMUBYTEN4 ); + return S_OK; + + case DXGI_FORMAT_P010: + assert( destImage.format == DXGI_FORMAT_Y210 ); + CONVERT_420_TO_422( uint16_t, XMUSHORTN4 ); + return S_OK; + + case DXGI_FORMAT_P016: + assert( destImage.format == DXGI_FORMAT_Y216 ); + CONVERT_420_TO_422( uint16_t, XMUSHORTN4 ); + return S_OK; + + case DXGI_FORMAT_NV11: + assert( destImage.format == DXGI_FORMAT_YUY2 ); + // Convert 4:1:1 to 4:2:2 + { + size_t rowPitch = srcImage.rowPitch; + + const uint8_t* sourceE = pSrc + srcImage.slicePitch; + const uint8_t* pSrcUV = pSrc + ( srcImage.height * rowPitch ); + + for( size_t y = 0; y < srcImage.height; ++y ) + { + const uint8_t* sPtrY = pSrc; + const uint8_t* sPtrUV = pSrcUV; + + XMUBYTEN4 * __restrict dPtr = reinterpret_cast(pDest); + + for( size_t x = 0; x < srcImage.width; x+= 4 ) + { + if ( (sPtrUV+1) >= sourceE ) break; + + uint8_t u = *(sPtrUV++); + uint8_t v = *(sPtrUV++); + + dPtr->x = *(sPtrY++); + dPtr->y = u; + dPtr->z = *(sPtrY++); + dPtr->w = v; + ++dPtr; + + dPtr->x = *(sPtrY++); + dPtr->y = u; + dPtr->z = *(sPtrY++); + dPtr->w = v; + ++dPtr; + } + + pSrc += rowPitch; + pSrcUV += (rowPitch >> 1); + + pDest += destImage.rowPitch; + } + } + return S_OK; + + default: + return E_UNEXPECTED; + } +} + +#undef CONVERT_420_TO_422 + + //===================================================================================== // Entry-points //===================================================================================== @@ -3296,7 +4201,8 @@ HRESULT Convert( const Image& srcImage, DXGI_FORMAT format, DWORD filter, float return E_POINTER; if ( IsCompressed(srcImage.format) || IsCompressed(format) - || IsVideo(srcImage.format) || IsVideo(format) + || IsPlanar(srcImage.format) || IsPlanar(format) + || IsPalettized(srcImage.format) || IsPalettized(format) || IsTypeless(srcImage.format) || IsTypeless(format) ) return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); @@ -3347,7 +4253,8 @@ HRESULT Convert( const Image* srcImages, size_t nimages, const TexMetadata& meta return E_INVALIDARG; if ( IsCompressed(metadata.format) || IsCompressed(format) - || IsVideo(metadata.format) || IsVideo(format) + || IsPlanar(metadata.format) || IsPlanar(format) + || IsPalettized(metadata.format) || IsPalettized(format) || IsTypeless(metadata.format) || IsTypeless(format) ) return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); @@ -3483,4 +4390,126 @@ HRESULT Convert( const Image* srcImages, size_t nimages, const TexMetadata& meta return S_OK; } + +//------------------------------------------------------------------------------------- +// Convert image from planar to single plane (image) +//------------------------------------------------------------------------------------- +_Use_decl_annotations_ +HRESULT ConvertToSinglePlane( const Image& srcImage, ScratchImage& image ) +{ + if ( !IsPlanar(srcImage.format) ) + return E_INVALIDARG; + + if ( !srcImage.pixels ) + return E_POINTER; + + DXGI_FORMAT format = _PlanarToSingle( srcImage.format ); + if ( format == DXGI_FORMAT_UNKNOWN ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + +#ifdef _M_X64 + if ( (srcImage.width > 0xFFFFFFFF) || (srcImage.height > 0xFFFFFFFF) ) + return E_INVALIDARG; +#endif + + HRESULT hr = image.Initialize2D( format, srcImage.width, srcImage.height, 1, 1 ); + if ( FAILED(hr) ) + return hr; + + const Image *rimage = image.GetImage( 0, 0, 0 ); + if ( !rimage ) + { + image.Release(); + return E_POINTER; + } + + hr = _ConvertToSinglePlane( srcImage, *rimage ); + if ( FAILED(hr) ) + { + image.Release(); + return hr; + } + + return S_OK; +} + + +//------------------------------------------------------------------------------------- +// Convert image from planar to single plane (complex) +//------------------------------------------------------------------------------------- +_Use_decl_annotations_ +HRESULT ConvertToSinglePlane( const Image* srcImages, size_t nimages, const TexMetadata& metadata, + ScratchImage& result ) +{ + if ( !srcImages || !nimages ) + return E_INVALIDARG; + + if ( metadata.IsVolumemap() ) + { + // Direct3D does not support any planar formats for Texture3D + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + } + + DXGI_FORMAT format = _PlanarToSingle( metadata.format ); + if ( format == DXGI_FORMAT_UNKNOWN ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + +#ifdef _M_X64 + if ( (metadata.width > 0xFFFFFFFF) || (metadata.height > 0xFFFFFFFF) ) + return E_INVALIDARG; +#endif + + TexMetadata mdata2 = metadata; + mdata2.format = format; + HRESULT hr = result.Initialize( mdata2 ); + if ( FAILED(hr) ) + return hr; + + if ( nimages != result.GetImageCount() ) + { + result.Release(); + return E_FAIL; + } + + const Image* dest = result.GetImages(); + if ( !dest ) + { + result.Release(); + return E_POINTER; + } + + for( size_t index=0; index < nimages; ++index ) + { + const Image& src = srcImages[ index ]; + if ( src.format != metadata.format ) + { + result.Release(); + return E_FAIL; + } + +#ifdef _M_X64 + if ( (src.width > 0xFFFFFFFF) || (src.height > 0xFFFFFFFF) ) + return E_FAIL; +#endif + + const Image& dst = dest[ index ]; + assert( dst.format == format ); + + if ( src.width != dst.width || src.height != dst.height ) + { + result.Release(); + return E_FAIL; + } + + hr = _ConvertToSinglePlane( src, dst ); + if ( FAILED(hr) ) + { + result.Release(); + return hr; + } + } + + return S_OK; +} + }; // namespace diff --git a/DirectXTex/DirectXTexD3D11.cpp b/DirectXTex/DirectXTexD3D11.cpp index 70fbfac..a98c83f 100644 --- a/DirectXTex/DirectXTexD3D11.cpp +++ b/DirectXTex/DirectXTexD3D11.cpp @@ -55,6 +55,11 @@ static HRESULT _Capture( _In_ ID3D11DeviceContext* pContext, _In_ ID3D11Resource } size_t lines = ComputeScanlines( metadata.format, height ); + if ( !lines ) + { + pContext->Unmap( pSource, dindex ); + return E_UNEXPECTED; + } for( size_t slice = 0; slice < depth; ++slice ) { @@ -124,6 +129,11 @@ static HRESULT _Capture( _In_ ID3D11DeviceContext* pContext, _In_ ID3D11Resource } size_t lines = ComputeScanlines( metadata.format, height ); + if ( !lines ) + { + pContext->Unmap( pSource, dindex ); + return E_UNEXPECTED; + } auto sptr = reinterpret_cast( mapped.pData ); uint8_t* dptr = img->pixels; @@ -168,9 +178,6 @@ bool IsSupportedTexture( ID3D11Device* pDevice, const TexMetadata& metadata ) if ( !IsValid( fmt ) ) return false; - if ( IsVideo(fmt) ) - return false; - switch( fmt ) { case DXGI_FORMAT_BC4_TYPELESS: diff --git a/DirectXTex/DirectXTexDDS.cpp b/DirectXTex/DirectXTexDDS.cpp index 0f9f3bd..00a4208 100644 --- a/DirectXTex/DirectXTexDDS.cpp +++ b/DirectXTex/DirectXTexDDS.cpp @@ -123,6 +123,9 @@ const LegacyDDS g_LegacyDDSMap[] = | CONV_FLAGS_4444, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x0f00, 0x00f0, 0x000f, 0x0000 } }, // D3DFMT_X4R4G4B4 (uses DXGI 1.2 format) { DXGI_FORMAT_B4G4R4A4_UNORM, CONV_FLAGS_EXPAND | CONV_FLAGS_44, { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 8, 0x0f, 0x00, 0x00, 0xf0 } }, // D3DFMT_A4L4 (uses DXGI 1.2 format) + + { DXGI_FORMAT_YUY2, CONV_FLAGS_NONE, DDSPF_YUY2 }, // D3DFMT_YUY2 (uses DXGI 1.2 format) + { DXGI_FORMAT_YUY2, CONV_FLAGS_SWIZZLE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('U','Y','V','Y'), 0, 0, 0, 0, 0 } }, // D3DFMT_UYVY (uses DXGI 1.2 format) }; // Note that many common DDS reader/writers (including D3DX) swap the @@ -134,8 +137,6 @@ const LegacyDDS g_LegacyDDSMap[] = // We do not support the following legacy Direct3D 9 formats: // BumpDuDv D3DFMT_V8U8, D3DFMT_Q8W8V8U8, D3DFMT_V16U16, D3DFMT_A2W10V10U10 // BumpLuminance D3DFMT_L6V5U5, D3DFMT_X8L8V8U8 -// FourCC "UYVY" D3DFMT_UYVY -// FourCC "YUY2" D3DFMT_YUY2 // FourCC 117 D3DFMT_CxV8U8 // ZBuffer D3DFMT_D16_LOCKABLE // FourCC 82 D3DFMT_D32F_LOCKABLE @@ -248,9 +249,9 @@ static HRESULT _DecodeDDSHeader( _In_reads_bytes_(size) LPCVOID pSource, size_t } metadata.format = d3d10ext->dxgiFormat; - if ( !IsValid( metadata.format ) ) + if ( !IsValid( metadata.format ) || IsPalettized( metadata.format ) ) { - return HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); } static_assert( TEX_MISC_TEXTURECUBE == DDS_RESOURCE_MISC_TEXTURECUBE, "DDS header mismatch"); @@ -440,7 +441,11 @@ _Use_decl_annotations_ HRESULT _EncodeDDSHeader( const TexMetadata& metadata, DWORD flags, LPVOID pDestination, size_t maxsize, size_t& required ) { - assert( IsValid( metadata.format ) && !IsVideo( metadata.format ) ); + if ( !IsValid( metadata.format ) ) + return E_INVALIDARG; + + if ( IsPalettized( metadata.format ) ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); if ( metadata.arraySize > 1 ) { @@ -480,7 +485,8 @@ HRESULT _EncodeDDSHeader( const TexMetadata& metadata, DWORD flags, case DXGI_FORMAT_B5G5R5A1_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_A1R5G5B5, sizeof(DDS_PIXELFORMAT) ); break; case DXGI_FORMAT_B8G8R8A8_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_A8R8G8B8, sizeof(DDS_PIXELFORMAT) ); break; // DXGI 1.1 case DXGI_FORMAT_B8G8R8X8_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_X8R8G8B8, sizeof(DDS_PIXELFORMAT) ); break; // DXGI 1.1 - case DXGI_FORMAT_B4G4R4A4_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_A4R4G4B4, sizeof(DDS_PIXELFORMAT) ); break; + case DXGI_FORMAT_B4G4R4A4_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_A4R4G4B4, sizeof(DDS_PIXELFORMAT) ); break; // DXGI 1.2 + case DXGI_FORMAT_YUY2: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_YUY2, sizeof(DDS_PIXELFORMAT) ); break; // DXGI 1.2 // Legacy D3DX formats using D3DFMT enum value as FourCC case DXGI_FORMAT_R32G32B32A32_FLOAT: @@ -723,7 +729,7 @@ static bool _LegacyExpandScanline( _Out_writes_bytes_(outSize) LPVOID pDestinati { assert( pDestination && outSize > 0 ); assert( pSource && inSize > 0 ); - assert( IsValid(outFormat) && !IsVideo(outFormat) ); + assert( IsValid(outFormat) && !IsPlanar(outFormat) && !IsPalettized(outFormat) ); switch( inFormat ) { @@ -1101,6 +1107,20 @@ static HRESULT _CopyImage( _In_reads_bytes_(size) const void* pPixels, _In_ size size_t csize = std::min( images[ index ].slicePitch, timages[ index ].slicePitch ); memcpy_s( pDest, images[ index ].slicePitch, pSrc, csize ); } + else if ( IsPlanar( metadata.format ) ) + { + size_t count = ComputeScanlines( metadata.format, images[ index ].height ); + if ( !count ) + return E_UNEXPECTED; + + size_t csize = std::min( dpitch, spitch ); + for( size_t h = 0; h < count; ++h ) + { + memcpy_s( pDest, dpitch, pSrc, csize ); + pSrc += spitch; + pDest += dpitch; + } + } else { for( size_t h = 0; h < images[ index ].height; ++h ) @@ -1175,6 +1195,11 @@ static HRESULT _CopyImage( _In_reads_bytes_(size) const void* pPixels, _In_ size size_t csize = std::min( images[ index ].slicePitch, timages[ index ].slicePitch ); memcpy_s( pDest, images[ index ].slicePitch, pSrc, csize ); } + else if ( IsPlanar( metadata.format ) ) + { + // Direct3D does not support any planar formats for Texture3D + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + } else { for( size_t h = 0; h < images[ index ].height; ++h ) @@ -1237,6 +1262,9 @@ static HRESULT _CopyImageInPlace( DWORD convFlags, _In_ const ScratchImage& imag const TexMetadata& metadata = image.GetMetadata(); + if ( IsPlanar( metadata.format ) ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + DWORD tflags = (convFlags & CONV_FLAGS_NOALPHA) ? TEXP_SCANLINE_SETALPHA : 0; if ( convFlags & CONV_FLAGS_SWIZZLE ) tflags |= TEXP_SCANLINE_LEGACY; diff --git a/DirectXTex/DirectXTexImage.cpp b/DirectXTex/DirectXTexImage.cpp index 76e91ca..7993258 100644 --- a/DirectXTex/DirectXTexImage.cpp +++ b/DirectXTex/DirectXTexImage.cpp @@ -256,9 +256,12 @@ ScratchImage& ScratchImage::operator= (ScratchImage&& moveFrom) _Use_decl_annotations_ HRESULT ScratchImage::Initialize( const TexMetadata& mdata ) { - if ( !IsValid(mdata.format) || IsVideo(mdata.format) ) + if ( !IsValid(mdata.format) ) return E_INVALIDARG; + if ( IsPalettized(mdata.format) ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + size_t mipLevels = mdata.mipLevels; switch( mdata.dimension ) @@ -267,6 +270,9 @@ HRESULT ScratchImage::Initialize( const TexMetadata& mdata ) if ( !mdata.width || mdata.height != 1 || mdata.depth != 1 || !mdata.arraySize ) return E_INVALIDARG; + if ( IsVideo(mdata.format) ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if ( !_CalculateMipLevels(mdata.width,1,mipLevels) ) return E_INVALIDARG; break; @@ -279,6 +285,9 @@ HRESULT ScratchImage::Initialize( const TexMetadata& mdata ) { if ( (mdata.arraySize % 6) != 0 ) return E_INVALIDARG; + + if ( IsVideo(mdata.format) ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); } if ( !_CalculateMipLevels(mdata.width,mdata.height,mipLevels) ) @@ -288,6 +297,9 @@ HRESULT ScratchImage::Initialize( const TexMetadata& mdata ) case TEX_DIMENSION_TEXTURE3D: if ( !mdata.width || !mdata.height || !mdata.depth || mdata.arraySize != 1 ) return E_INVALIDARG; + + if ( IsVideo(mdata.format) || IsPlanar(mdata.format) || IsDepthStencil(mdata.format) ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); if ( !_CalculateMipLevels3D(mdata.width,mdata.height,mdata.depth,mipLevels) ) return E_INVALIDARG; @@ -338,9 +350,12 @@ HRESULT ScratchImage::Initialize( const TexMetadata& mdata ) _Use_decl_annotations_ HRESULT ScratchImage::Initialize1D( DXGI_FORMAT fmt, size_t length, size_t arraySize, size_t mipLevels ) { - if ( !IsValid(fmt) || IsVideo(fmt) || !length || !arraySize ) + if ( !length || !arraySize ) return E_INVALIDARG; + if ( IsVideo(fmt) ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + // 1D is a special case of the 2D case HRESULT hr = Initialize2D( fmt, length, 1, arraySize, mipLevels ); if ( FAILED(hr) ) @@ -354,9 +369,12 @@ 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 ) { - if ( !IsValid(fmt) || IsVideo(fmt) || !width || !height || !arraySize ) + if ( !IsValid(fmt) || !width || !height || !arraySize ) return E_INVALIDARG; + if ( IsPalettized(fmt) ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if ( !_CalculateMipLevels(width,height,mipLevels) ) return E_INVALIDARG; @@ -401,9 +419,12 @@ 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 ) { - if ( !IsValid(fmt) || IsVideo(fmt) || !width || !height || !depth ) + if ( !IsValid(fmt) || !width || !height || !depth ) return E_INVALIDARG; + if ( IsVideo(fmt) || IsPlanar(fmt) || IsDepthStencil(fmt) ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if ( !_CalculateMipLevels3D(width,height,depth,mipLevels) ) return E_INVALIDARG; @@ -451,8 +472,11 @@ 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 ) { - if ( !IsValid(fmt) || IsVideo(fmt) || !width || !height || !nCubes ) + if ( !width || !height || !nCubes ) return E_INVALIDARG; + + if ( IsVideo(fmt) ) + 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 ); @@ -474,6 +498,10 @@ HRESULT ScratchImage::InitializeFromImage( const Image& srcImage, bool allow1D ) if ( FAILED(hr) ) return hr; + size_t rowCount = ComputeScanlines( srcImage.format, srcImage.height ); + if ( !rowCount ) + return E_UNEXPECTED; + const uint8_t* sptr = reinterpret_cast( srcImage.pixels ); if ( !sptr ) return E_POINTER; @@ -482,11 +510,16 @@ HRESULT ScratchImage::InitializeFromImage( const Image& srcImage, bool allow1D ) if ( !dptr ) return E_POINTER; - for( size_t y = 0; y < srcImage.height; ++y ) + size_t spitch = srcImage.rowPitch; + size_t dpitch = _image[0].rowPitch; + + size_t size = std::min( dpitch, spitch ); + + for( size_t y = 0; y < rowCount; ++y ) { - _CopyScanline( dptr, _image[0].rowPitch, sptr, srcImage.rowPitch, srcImage.format, TEXP_SCANLINE_NONE ); - sptr += srcImage.rowPitch; - dptr += _image[0].rowPitch; + memcpy_s( dptr, dpitch, sptr, size ); + sptr += spitch; + dptr += dpitch; } return S_OK; @@ -521,6 +554,10 @@ HRESULT ScratchImage::InitializeArrayFromImages( const Image* images, size_t nIm if ( FAILED(hr) ) return hr; + size_t rowCount = ComputeScanlines( format, height ); + if ( !rowCount ) + return E_UNEXPECTED; + for( size_t index=0; index < nImages; ++index ) { auto sptr = reinterpret_cast( images[index].pixels ); @@ -532,11 +569,16 @@ HRESULT ScratchImage::InitializeArrayFromImages( const Image* images, size_t nIm if ( !dptr ) return E_POINTER; - for( size_t y = 0; y < height; ++y ) + size_t spitch = images[index].rowPitch; + size_t dpitch = _image[index].rowPitch; + + size_t size = std::min( dpitch, spitch ); + + for( size_t y = 0; y < rowCount; ++y ) { - _CopyScanline( dptr, _image[index].rowPitch, sptr, images[index].rowPitch, format, TEXP_SCANLINE_NONE ); - sptr += images[index].rowPitch; - dptr += _image[index].rowPitch; + memcpy_s( dptr, dpitch, sptr, size ); + sptr += spitch; + dptr += dpitch; } } @@ -553,6 +595,9 @@ HRESULT ScratchImage::InitializeCubeFromImages( const Image* images, size_t nIma if ( ( nImages % 6 ) != 0 ) return E_INVALIDARG; + if ( IsVideo(images[0].format) || IsPalettized(images[0].format) ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + HRESULT hr = InitializeArrayFromImages( images, nImages, false ); if ( FAILED(hr) ) return hr; @@ -588,6 +633,10 @@ HRESULT ScratchImage::Initialize3DFromImages( const Image* images, size_t depth if ( FAILED(hr) ) return hr; + size_t rowCount = ComputeScanlines( format, height ); + if ( !rowCount ) + return E_UNEXPECTED; + for( size_t slice=0; slice < depth; ++slice ) { auto sptr = reinterpret_cast( images[slice].pixels ); @@ -599,11 +648,16 @@ HRESULT ScratchImage::Initialize3DFromImages( const Image* images, size_t depth if ( !dptr ) return E_POINTER; - for( size_t y = 0; y < height; ++y ) + size_t spitch = images[slice].rowPitch; + size_t dpitch = _image[slice].rowPitch; + + size_t size = std::min( dpitch, spitch ); + + for( size_t y = 0; y < rowCount; ++y ) { - _CopyScanline( dptr, _image[slice].rowPitch, sptr, images[slice].rowPitch, format, TEXP_SCANLINE_NONE ); - sptr += images[slice].rowPitch; - dptr += _image[slice].rowPitch; + memcpy_s( dptr, dpitch, sptr, size ); + sptr += spitch; + dptr += dpitch; } } @@ -636,12 +690,13 @@ bool ScratchImage::OverrideFormat( DXGI_FORMAT f ) if ( !_image ) return false; - if ( !IsValid( f ) || IsVideo( f ) ) + if ( !IsValid( f ) || IsPlanar( f ) || IsPalettized( f ) ) return false; if ( ( BitsPerPixel( f ) != BitsPerPixel( _metadata.format ) ) || ( IsCompressed( f ) != IsCompressed( _metadata.format ) ) - || ( IsPacked( f ) != IsPacked( _metadata.format ) ) ) + || ( IsPacked( f ) != IsPacked( _metadata.format ) ) + || ( IsVideo( f ) != IsVideo( _metadata.format ) ) ) { // Can't change the effective pitch of the format this way return false; diff --git a/DirectXTex/DirectXTexMipmaps.cpp b/DirectXTex/DirectXTexMipmaps.cpp index ff08a0a..c8e8e2c 100644 --- a/DirectXTex/DirectXTexMipmaps.cpp +++ b/DirectXTex/DirectXTexMipmaps.cpp @@ -2489,7 +2489,7 @@ HRESULT GenerateMipMaps( const Image& baseImage, DWORD filter, size_t levels, Sc if ( !_CalculateMipLevels(baseImage.width, baseImage.height, levels) ) return E_INVALIDARG; - if ( IsCompressed( baseImage.format ) || IsVideo( baseImage.format ) ) + if ( IsCompressed(baseImage.format) || IsTypeless(baseImage.format) || IsPlanar(baseImage.format) || IsPalettized(baseImage.format) ) { return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); } @@ -2515,9 +2515,9 @@ HRESULT GenerateMipMaps( const Image& baseImage, DWORD filter, size_t levels, Sc if ( _DXGIToWIC( baseImage.format, pfGUID, true ) ) { // Case 1: Base image format is supported by Windows Imaging Component - HRESULT hr = (baseImage.height > 1 || !allow1D) - ? mipChain.Initialize2D( baseImage.format, baseImage.width, baseImage.height, 1, levels ) - : mipChain.Initialize1D( baseImage.format, baseImage.width, 1, levels ); + hr = (baseImage.height > 1 || !allow1D) + ? mipChain.Initialize2D( baseImage.format, baseImage.width, baseImage.height, 1, levels ) + : mipChain.Initialize1D( baseImage.format, baseImage.width, 1, levels ); if ( FAILED(hr) ) return hr; @@ -2528,7 +2528,7 @@ HRESULT GenerateMipMaps( const Image& baseImage, DWORD filter, size_t levels, Sc // Case 2: Base image format is not supported by WIC, so we have to convert, generate, and convert back assert( baseImage.format != DXGI_FORMAT_R32G32B32A32_FLOAT ); ScratchImage temp; - HRESULT hr = _ConvertToR32G32B32A32( baseImage, temp ); + hr = _ConvertToR32G32B32A32( baseImage, temp ); if ( FAILED(hr) ) return hr; @@ -2645,7 +2645,7 @@ HRESULT GenerateMipMaps( const Image* srcImages, size_t nimages, const TexMetada return E_INVALIDARG; if ( metadata.IsVolumemap() - || IsCompressed( metadata.format ) || IsVideo( metadata.format ) ) + || IsCompressed(metadata.format) || IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format) ) return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); if ( !_CalculateMipLevels(metadata.width, metadata.height, levels) ) @@ -2697,7 +2697,7 @@ HRESULT GenerateMipMaps( const Image* srcImages, size_t nimages, const TexMetada // Case 1: Base image format is supported by Windows Imaging Component TexMetadata mdata2 = metadata; mdata2.mipLevels = levels; - HRESULT hr = mipChain.Initialize( mdata2 ); + hr = mipChain.Initialize( mdata2 ); if ( FAILED(hr) ) return hr; @@ -2722,7 +2722,7 @@ HRESULT GenerateMipMaps( const Image* srcImages, size_t nimages, const TexMetada mdata2.mipLevels = levels; mdata2.format = DXGI_FORMAT_R32G32B32A32_FLOAT; ScratchImage tMipChain; - HRESULT hr = tMipChain.Initialize( mdata2 ); + hr = tMipChain.Initialize( mdata2 ); if ( FAILED(hr) ) return hr; @@ -2869,11 +2869,8 @@ HRESULT GenerateMipMaps3D( const Image* baseImages, size_t depth, DWORD filter, } } - if ( IsCompressed( format ) ) - { - // We don't support generating mipmaps from compressed images, as those should be generated before compression + if ( IsCompressed(format) || IsTypeless(format) || IsPlanar(format) || IsPalettized(format) ) return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); - } static_assert( TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK" ); @@ -2954,7 +2951,7 @@ HRESULT GenerateMipMaps3D( const Image* srcImages, size_t nimages, const TexMeta return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); if ( !metadata.IsVolumemap() - || IsCompressed( metadata.format ) || IsVideo( metadata.format ) ) + || IsCompressed(metadata.format) || IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format) ) return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); if ( !_CalculateMipLevels3D(metadata.width, metadata.height, metadata.depth, levels) ) diff --git a/DirectXTex/DirectXTexMisc.cpp b/DirectXTex/DirectXTexMisc.cpp index 6f7b99f..1492622 100644 --- a/DirectXTex/DirectXTexMisc.cpp +++ b/DirectXTex/DirectXTexMisc.cpp @@ -176,7 +176,9 @@ HRESULT CopyRectangle( const Image& srcImage, const Rect& srcRect, const Image& if ( !srcImage.pixels || !dstImage.pixels ) return E_POINTER; - if ( IsCompressed( srcImage.format ) || IsCompressed( dstImage.format ) ) + if ( IsCompressed( srcImage.format ) || IsCompressed( dstImage.format ) + || IsPlanar( srcImage.format ) || IsPlanar( dstImage.format ) + || IsPalettized( srcImage.format ) || IsPalettized( dstImage.format ) ) return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); // Validate rectangle/offset @@ -284,6 +286,10 @@ HRESULT ComputeMSE( const Image& image1, const Image& image2, float& mse, float* if ( image1.width != image2.width || image1.height != image2.height ) return E_INVALIDARG; + if ( IsPlanar( image1.format ) || IsPlanar( image2.format ) + || IsPalettized( image1.format ) || IsPalettized( image2.format ) ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if ( IsCompressed(image1.format) ) { if ( IsCompressed(image2.format) ) diff --git a/DirectXTex/DirectXTexNormalMaps.cpp b/DirectXTex/DirectXTexNormalMaps.cpp index 7822bdf..cf436c1 100644 --- a/DirectXTex/DirectXTexNormalMaps.cpp +++ b/DirectXTex/DirectXTexNormalMaps.cpp @@ -79,14 +79,12 @@ static HRESULT _ComputeNMap( _In_ const Image& srcImage, _In_ DWORD flags, _In_ if ( !srcImage.pixels || !normalMap.pixels ) return E_INVALIDARG; - assert( !IsCompressed(format) && !IsTypeless( format ) ); - const DWORD convFlags = _GetConvertFlags( format ); if ( !convFlags ) return E_FAIL; if ( !( convFlags & (CONVF_UNORM | CONVF_SNORM | CONVF_FLOAT) ) ) - HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); const size_t width = srcImage.width; const size_t height = srcImage.height; @@ -257,7 +255,7 @@ _Use_decl_annotations_ HRESULT ComputeNormalMap( const Image& srcImage, DWORD flags, float amplitude, DXGI_FORMAT format, ScratchImage& normalMap ) { - if ( !srcImage.pixels || !IsValid(format) || IsCompressed( format ) || IsTypeless( format ) ) + if ( !srcImage.pixels || !IsValid(format) ) return E_INVALIDARG; static_assert( CNMAP_CHANNEL_RED == 0x1, "CNMAP_CHANNEL_ flag values don't match mask" ); @@ -275,7 +273,10 @@ HRESULT ComputeNormalMap( const Image& srcImage, DWORD flags, float amplitude, return E_INVALIDARG; } - if ( IsCompressed( srcImage.format ) || IsTypeless( srcImage.format ) ) + if ( IsCompressed(format) || IsCompressed(srcImage.format) + || IsTypeless(format) || IsTypeless(srcImage.format) + || IsPlanar(format) || IsPlanar(srcImage.format) + || IsPalettized(format) || IsPalettized(srcImage.format) ) return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); // Setup target image @@ -306,11 +307,14 @@ _Use_decl_annotations_ HRESULT ComputeNormalMap( const Image* srcImages, size_t nimages, const TexMetadata& metadata, DWORD flags, float amplitude, DXGI_FORMAT format, ScratchImage& normalMaps ) { - if ( !srcImages || !nimages ) + if ( !srcImages || !nimages || !IsValid(format) ) return E_INVALIDARG; - if ( !IsValid(format) || IsCompressed(format) || IsTypeless(format) ) - return E_INVALIDARG; + if ( IsCompressed(format) || IsCompressed(metadata.format) + || IsTypeless(format) || IsTypeless(metadata.format) + || IsPlanar(format) || IsPlanar(metadata.format) + || IsPalettized(format) || IsPalettized(metadata.format) ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); static_assert( CNMAP_CHANNEL_RED == 0x1, "CNMAP_CHANNEL_ flag values don't match mask" ); switch( flags & 0xf ) diff --git a/DirectXTex/DirectXTexP.h b/DirectXTex/DirectXTexP.h index 73af860..32f6225 100644 --- a/DirectXTex/DirectXTexP.h +++ b/DirectXTex/DirectXTexP.h @@ -141,6 +141,7 @@ namespace DirectX CONVF_XR = 0x200, CONVF_PACKED = 0x400, CONVF_BC = 0x800, + CONVF_YUV = 0x1000, CONVF_R = 0x10000, CONVF_G = 0x20000, CONVF_B = 0x40000, diff --git a/DirectXTex/DirectXTexPMAlpha.cpp b/DirectXTex/DirectXTexPMAlpha.cpp index ce06688..2c7deda 100644 --- a/DirectXTex/DirectXTexPMAlpha.cpp +++ b/DirectXTex/DirectXTexPMAlpha.cpp @@ -114,7 +114,8 @@ HRESULT PremultiplyAlpha( const Image& srcImage, DWORD flags, ScratchImage& imag return E_POINTER; if ( IsCompressed(srcImage.format) - || IsVideo(srcImage.format) + || IsPlanar(srcImage.format) + || IsPalettized(srcImage.format) || IsTypeless(srcImage.format) || !HasAlpha(srcImage.format) ) return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); @@ -156,7 +157,8 @@ HRESULT PremultiplyAlpha( const Image* srcImages, size_t nimages, const TexMetad return E_INVALIDARG; if ( IsCompressed(metadata.format) - || IsVideo(metadata.format) + || IsPlanar(metadata.format) + || IsPalettized(metadata.format) || IsTypeless(metadata.format) || !HasAlpha(metadata.format) ) return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); diff --git a/DirectXTex/DirectXTexTGA.cpp b/DirectXTex/DirectXTexTGA.cpp index 609fc96..2960156 100644 --- a/DirectXTex/DirectXTexTGA.cpp +++ b/DirectXTex/DirectXTexTGA.cpp @@ -738,8 +738,6 @@ static HRESULT _CopyPixels( _In_reads_bytes_(size) LPCVOID pSource, size_t size, //------------------------------------------------------------------------------------- static HRESULT _EncodeTGAHeader( _In_ const Image& image, _Out_ TGA_HEADER& header, _Inout_ DWORD& convFlags ) { - assert( IsValid( image.format ) && !IsVideo( image.format ) ); - memset( &header, 0, sizeof(TGA_HEADER) ); if ( (image.width > 0xFFFF) diff --git a/DirectXTex/DirectXTexUtil.cpp b/DirectXTex/DirectXTexUtil.cpp index 168cdd8..d98626b 100644 --- a/DirectXTex/DirectXTexUtil.cpp +++ b/DirectXTex/DirectXTexUtil.cpp @@ -276,7 +276,7 @@ REFGUID GetWICCodec( WICCodecs codec ) _Use_decl_annotations_ size_t BitsPerPixel( DXGI_FORMAT fmt ) { - switch( fmt ) + switch( static_cast(fmt) ) { case DXGI_FORMAT_R32G32B32A32_TYPELESS: case DXGI_FORMAT_R32G32B32A32_FLOAT: @@ -304,6 +304,9 @@ size_t BitsPerPixel( DXGI_FORMAT fmt ) case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + case DXGI_FORMAT_Y416: + case DXGI_FORMAT_Y210: + case DXGI_FORMAT_Y216: return 64; case DXGI_FORMAT_R10G10B10A2_TYPELESS: @@ -341,8 +344,20 @@ size_t BitsPerPixel( DXGI_FORMAT fmt ) case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: case DXGI_FORMAT_B8G8R8X8_TYPELESS: case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + case DXGI_FORMAT_AYUV: + case DXGI_FORMAT_Y410: + case DXGI_FORMAT_YUY2: + case 116 /* DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT */: + case 117 /* DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT */: return 32; + case DXGI_FORMAT_P010: + case DXGI_FORMAT_P016: + case 118 /* DXGI_FORMAT_D16_UNORM_S8_UINT */: + case 119 /* DXGI_FORMAT_R16_UNORM_X8_TYPELESS */: + case 120 /* DXGI_FORMAT_X16_TYPELESS_G8_UINT */: + return 24; + case DXGI_FORMAT_R8G8_TYPELESS: case DXGI_FORMAT_R8G8_UNORM: case DXGI_FORMAT_R8G8_UINT: @@ -357,14 +372,24 @@ size_t BitsPerPixel( DXGI_FORMAT fmt ) case DXGI_FORMAT_R16_SINT: case DXGI_FORMAT_B5G6R5_UNORM: case DXGI_FORMAT_B5G5R5A1_UNORM: + case DXGI_FORMAT_A8P8: + case DXGI_FORMAT_B4G4R4A4_UNORM: return 16; + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_420_OPAQUE: + case DXGI_FORMAT_NV11: + return 12; + case DXGI_FORMAT_R8_TYPELESS: case DXGI_FORMAT_R8_UNORM: case DXGI_FORMAT_R8_UINT: case DXGI_FORMAT_R8_SNORM: case DXGI_FORMAT_R8_SINT: case DXGI_FORMAT_A8_UNORM: + case DXGI_FORMAT_AI44: + case DXGI_FORMAT_IA44: + case DXGI_FORMAT_P8: return 8; case DXGI_FORMAT_R1_UNORM: @@ -395,11 +420,6 @@ size_t BitsPerPixel( DXGI_FORMAT fmt ) case DXGI_FORMAT_BC7_UNORM_SRGB: return 8; - case DXGI_FORMAT_B4G4R4A4_UNORM: - return 16; - - // We don't support the video formats ( see IsVideo function ) - default: return 0; } @@ -413,7 +433,7 @@ size_t BitsPerPixel( DXGI_FORMAT fmt ) _Use_decl_annotations_ size_t BitsPerColor( DXGI_FORMAT fmt ) { - switch( fmt ) + switch( static_cast(fmt) ) { case DXGI_FORMAT_R32G32B32A32_TYPELESS: case DXGI_FORMAT_R32G32B32A32_FLOAT: @@ -466,6 +486,9 @@ size_t BitsPerColor( DXGI_FORMAT fmt ) case DXGI_FORMAT_BC6H_TYPELESS: case DXGI_FORMAT_BC6H_UF16: case DXGI_FORMAT_BC6H_SF16: + case DXGI_FORMAT_Y416: + case DXGI_FORMAT_P016: + case DXGI_FORMAT_Y216: return 16; case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: @@ -478,6 +501,9 @@ size_t BitsPerColor( DXGI_FORMAT fmt ) case DXGI_FORMAT_R10G10B10A2_UNORM: case DXGI_FORMAT_R10G10B10A2_UINT: case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + case DXGI_FORMAT_Y410: + case DXGI_FORMAT_P010: + case DXGI_FORMAT_Y210: return 10; case DXGI_FORMAT_R8G8B8A8_TYPELESS: @@ -511,6 +537,11 @@ size_t BitsPerColor( DXGI_FORMAT fmt ) case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: case DXGI_FORMAT_B8G8R8X8_TYPELESS: case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + case DXGI_FORMAT_AYUV: + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_420_OPAQUE: + case DXGI_FORMAT_YUY2: + case DXGI_FORMAT_NV11: return 8; case DXGI_FORMAT_BC7_TYPELESS: @@ -536,11 +567,26 @@ size_t BitsPerColor( DXGI_FORMAT fmt ) case DXGI_FORMAT_B4G4R4A4_UNORM: return 4; - // We don't support the video formats ( see IsVideo function ) - case DXGI_FORMAT_R1_UNORM: return 1; + case 116 /* DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT */: + case 117 /* DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT */: + // These are Xbox One platform specific types + return 10; + + case 118 /* DXGI_FORMAT_D16_UNORM_S8_UINT */: + case 119 /* DXGI_FORMAT_R16_UNORM_X8_TYPELESS */: + case 120 /* DXGI_FORMAT_X16_TYPELESS_G8_UINT */: + // These are Xbox One platform specific types + return 16; + + case DXGI_FORMAT_AI44: + case DXGI_FORMAT_IA44: + case DXGI_FORMAT_P8: + case DXGI_FORMAT_A8P8: + // Palettized formats return 0 for this function + default: return 0; } @@ -555,7 +601,7 @@ _Use_decl_annotations_ void ComputePitch( DXGI_FORMAT fmt, size_t width, size_t height, size_t& rowPitch, size_t& slicePitch, DWORD flags ) { - assert( IsValid(fmt) && !IsVideo(fmt) ); + assert( IsValid(fmt) ); if ( IsCompressed(fmt) ) { @@ -573,10 +619,28 @@ void ComputePitch( DXGI_FORMAT fmt, size_t width, size_t height, } else if ( IsPacked(fmt) ) { - rowPitch = ( ( width + 1 ) >> 1) * 4; + size_t bpe = ( fmt == DXGI_FORMAT_Y210 || fmt == DXGI_FORMAT_Y216 ) ? 8 : 4; + rowPitch = ( ( width + 1 ) >> 1 ) * bpe; slicePitch = rowPitch * height; } + else if ( fmt == DXGI_FORMAT_NV11 ) + { + rowPitch = ( ( width + 3 ) >> 2 ) * 4; + + // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data + slicePitch = rowPitch * height * 2; + } + else if ( IsPlanar(fmt) ) + { + size_t bpe = ( fmt == DXGI_FORMAT_P010 || fmt == DXGI_FORMAT_P016 + || fmt == DXGI_FORMAT(118 /* DXGI_FORMAT_D16_UNORM_S8_UINT */) + || fmt == DXGI_FORMAT(119 /* DXGI_FORMAT_R16_UNORM_X8_TYPELESS */) + || fmt == DXGI_FORMAT(120 /* DXGI_FORMAT_X16_TYPELESS_G8_UINT */) ) ? 4 : 2; + rowPitch = ( ( width + 1 ) >> 1 ) * bpe; + + slicePitch = rowPitch * ( height + ( ( height + 1 ) >> 1 ) ); + } else { size_t bpp; diff --git a/Texconv/texconv.cpp b/Texconv/texconv.cpp index 53ac9ff..874cb20 100644 --- a/Texconv/texconv.cpp +++ b/Texconv/texconv.cpp @@ -180,6 +180,18 @@ SValue g_pFormats[] = DEFFMT(BC7_UNORM_SRGB), // DXGI 1.2 formats + DEFFMT(AYUV), + DEFFMT(Y410), + DEFFMT(Y416), + DEFFMT(NV12), + DEFFMT(P010), + DEFFMT(P016), + DEFFMT(420_OPAQUE), + DEFFMT(YUY2), + DEFFMT(Y210), + DEFFMT(Y216), + DEFFMT(NV11), + // No support for legacy paletted video formats (AI44, IA44, P8, A8P8) DEFFMT(B4G4R4A4_UNORM), { nullptr, DXGI_FORMAT_UNKNOWN } @@ -897,7 +909,6 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) PrintInfo( info ); size_t tMips = ( !mipLevels && info.mipLevels > 1 ) ? info.mipLevels : mipLevels; - DXGI_FORMAT tformat = ( format == DXGI_FORMAT_UNKNOWN ) ? info.format : format; bool sizewarn = false; @@ -933,6 +944,49 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) wprintf( L" as"); fflush(stdout); + // --- Planar ------------------------------------------------------------------ + if ( IsPlanar( info.format ) ) + { + const Image* img = image->GetImage(0,0,0); + assert( img ); + size_t nimg = image->GetImageCount(); + + ScratchImage *timage = new ScratchImage; + if ( !timage ) + { + wprintf( L" ERROR: Memory allocation failed\n" ); + delete image; + goto LError; + } + + hr = ConvertToSinglePlane( img, nimg, info, *timage ); + if ( FAILED(hr) ) + { + wprintf( L" FAILED [converttosingeplane] (%x)\n", hr); + delete timage; + delete image; + continue; + } + + const TexMetadata& tinfo = timage->GetMetadata(); + + info.format = tinfo.format; + + assert( info.width == tinfo.width ); + assert( info.height == tinfo.height ); + assert( info.depth == tinfo.depth ); + assert( info.arraySize == tinfo.arraySize ); + assert( info.mipLevels == tinfo.mipLevels ); + assert( info.miscFlags == tinfo.miscFlags ); + assert( info.miscFlags2 == tinfo.miscFlags2 ); + assert( info.dimension == tinfo.dimension ); + + delete image; + image = timage; + } + + DXGI_FORMAT tformat = ( format == DXGI_FORMAT_UNKNOWN ) ? info.format : format; + // --- Decompress -------------------------------------------------------------- if ( IsCompressed( info.format ) ) {