From 9f13dd26f9fafb5a2304870279aeb5eb155a8ac1 Mon Sep 17 00:00:00 2001 From: walbourn_cp Date: Tue, 4 Feb 2014 12:33:47 -0800 Subject: [PATCH] DDSTextureLoader/ScreenGrab: Updated with support for Direct3D 11 video formats including legacy 'YUY2' DDS files --- DDSTextureLoader/DDSTextureLoader.cpp | 114 +++++++++++++++++++++++--- ScreenGrab/ScreenGrab.cpp | 108 ++++++++++++++++++++++-- 2 files changed, 203 insertions(+), 19 deletions(-) diff --git a/DDSTextureLoader/DDSTextureLoader.cpp b/DDSTextureLoader/DDSTextureLoader.cpp index 3bfca4f..6f635e5 100644 --- a/DDSTextureLoader/DDSTextureLoader.cpp +++ b/DDSTextureLoader/DDSTextureLoader.cpp @@ -300,6 +300,9 @@ static size_t BitsPerPixel( _In_ 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: @@ -337,8 +340,15 @@ static size_t BitsPerPixel( _In_ 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: return 32; + case DXGI_FORMAT_P010: + case DXGI_FORMAT_P016: + return 24; + case DXGI_FORMAT_R8G8_TYPELESS: case DXGI_FORMAT_R8G8_UNORM: case DXGI_FORMAT_R8G8_UINT: @@ -353,15 +363,24 @@ static size_t BitsPerPixel( _In_ 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: @@ -392,6 +411,21 @@ static size_t BitsPerPixel( _In_ DXGI_FORMAT fmt ) case DXGI_FORMAT_BC7_UNORM_SRGB: return 8; +#if defined(_XBOX_ONE) && defined(_TITLE) + + case DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT: + case DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT: + return 32; + +#if MONOLITHIC + case DXGI_FORMAT_D16_UNORM_S8_UINT: + case DXGI_FORMAT_R16_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X16_TYPELESS_G8_UINT: + return 24; +#endif + +#endif // _XBOX_ONE && _TITLE + default: return 0; } @@ -413,8 +447,9 @@ static void GetSurfaceInfo( _In_ size_t width, size_t numRows = 0; bool bc = false; - bool packed = false; - size_t bcnumBytesPerBlock = 0; + bool packed = false; + bool planar = false; + size_t bpe = 0; switch (fmt) { case DXGI_FORMAT_BC1_TYPELESS: @@ -424,7 +459,7 @@ static void GetSurfaceInfo( _In_ size_t width, case DXGI_FORMAT_BC4_UNORM: case DXGI_FORMAT_BC4_SNORM: bc=true; - bcnumBytesPerBlock = 8; + bpe = 8; break; case DXGI_FORMAT_BC2_TYPELESS: @@ -443,13 +478,44 @@ static void GetSurfaceInfo( _In_ size_t width, case DXGI_FORMAT_BC7_UNORM: case DXGI_FORMAT_BC7_UNORM_SRGB: bc = true; - bcnumBytesPerBlock = 16; + bpe = 16; break; case DXGI_FORMAT_R8G8_B8G8_UNORM: case DXGI_FORMAT_G8R8_G8B8_UNORM: + case DXGI_FORMAT_YUY2: packed = true; + bpe = 4; break; + + case DXGI_FORMAT_Y210: + case DXGI_FORMAT_Y216: + packed = true; + bpe = 8; + break; + + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_420_OPAQUE: + planar = true; + bpe = 2; + break; + + case DXGI_FORMAT_P010: + case DXGI_FORMAT_P016: + planar = true; + bpe = 4; + break; + +#if defined(_XBOX_ONE) && defined(_TITLE) && MONOLITHIC + + case DXGI_FORMAT_D16_UNORM_S8_UINT: + case DXGI_FORMAT_R16_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X16_TYPELESS_G8_UINT: + planar = true; + bpe = 4; + break; + +#endif } if (bc) @@ -464,22 +530,36 @@ static void GetSurfaceInfo( _In_ size_t width, { numBlocksHigh = std::max( 1, (height + 3) / 4 ); } - rowBytes = numBlocksWide * bcnumBytesPerBlock; + rowBytes = numBlocksWide * bpe; numRows = numBlocksHigh; + numBytes = rowBytes * numBlocksHigh; } else if (packed) { - rowBytes = ( ( width + 1 ) >> 1 ) * 4; + rowBytes = ( ( width + 1 ) >> 1 ) * bpe; numRows = height; + numBytes = rowBytes * height; + } + else if ( fmt == DXGI_FORMAT_NV11 ) + { + rowBytes = ( ( width + 1 ) >> 1 ) * 2; + numBytes = rowBytes * ( ( height + 1 ) >> 1 ) * 4; + numRows = height * 2; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data + } + else if (planar) + { + rowBytes = ( ( width + 1 ) >> 1 ) * bpe; + numBytes = ( rowBytes * height ) + ( ( rowBytes * height + 1 ) >> 1 ); + numRows = height + ( ( height + 1 ) >> 1 ); } else { size_t bpp = BitsPerPixel( fmt ); rowBytes = ( width * bpp + 7 ) / 8; // round up to nearest byte numRows = height; + numBytes = rowBytes * height; } - numBytes = rowBytes * numRows; if (outNumBytes) { *outNumBytes = numBytes; @@ -671,6 +751,11 @@ static DXGI_FORMAT GetDXGIFormat( const DDS_PIXELFORMAT& ddpf ) return DXGI_FORMAT_G8R8_G8B8_UNORM; } + if (MAKEFOURCC('Y','U','Y','2') == ddpf.fourCC) + { + return DXGI_FORMAT_YUY2; + } + // Check for D3DFORMAT enums being set here switch( ddpf.fourCC ) { @@ -764,7 +849,6 @@ static HRESULT FillInitData( _In_ size_t width, size_t NumBytes = 0; size_t RowBytes = 0; - size_t NumRows = 0; const uint8_t* pSrcBits = bitData; const uint8_t* pEndBits = bitData + bitSize; @@ -781,7 +865,7 @@ static HRESULT FillInitData( _In_ size_t width, format, &NumBytes, &RowBytes, - &NumRows + nullptr ); if ( (mipCount <= 1) || !maxsize || (w <= maxsize && h <= maxsize && d <= maxsize) ) @@ -1114,9 +1198,19 @@ static HRESULT CreateTextureFromDDS( _In_ ID3D11Device* d3dDevice, return HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); } - if (BitsPerPixel( d3d10ext->dxgiFormat ) == 0) + switch( d3d10ext->dxgiFormat ) { + case DXGI_FORMAT_AI44: + case DXGI_FORMAT_IA44: + case DXGI_FORMAT_P8: + case DXGI_FORMAT_A8P8: return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + + default: + if ( BitsPerPixel( d3d10ext->dxgiFormat ) == 0 ) + { + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + } } format = d3d10ext->dxgiFormat; diff --git a/ScreenGrab/ScreenGrab.cpp b/ScreenGrab/ScreenGrab.cpp index a3091ff..ba2ced1 100644 --- a/ScreenGrab/ScreenGrab.cpp +++ b/ScreenGrab/ScreenGrab.cpp @@ -146,6 +146,9 @@ static const DDS_PIXELFORMAT DDSPF_R8G8_B8G8 = static const DDS_PIXELFORMAT DDSPF_G8R8_G8B8 = { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('G','R','G','B'), 0, 0, 0, 0, 0 }; +static const DDS_PIXELFORMAT DDSPF_YUY2 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('Y','U','Y','2'), 0, 0, 0, 0, 0 }; + static const DDS_PIXELFORMAT DDSPF_A8R8G8B8 = { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }; @@ -226,6 +229,9 @@ static size_t BitsPerPixel( _In_ 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: @@ -263,8 +269,15 @@ static size_t BitsPerPixel( _In_ 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: return 32; + case DXGI_FORMAT_P010: + case DXGI_FORMAT_P016: + return 24; + case DXGI_FORMAT_R8G8_TYPELESS: case DXGI_FORMAT_R8G8_UNORM: case DXGI_FORMAT_R8G8_UINT: @@ -279,15 +292,24 @@ static size_t BitsPerPixel( _In_ 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: @@ -318,6 +340,21 @@ static size_t BitsPerPixel( _In_ DXGI_FORMAT fmt ) case DXGI_FORMAT_BC7_UNORM_SRGB: return 8; +#if defined(_XBOX_ONE) && defined(_TITLE) + + case DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT: + case DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT: + return 32; + +#if MONOLITHIC + case DXGI_FORMAT_D16_UNORM_S8_UINT: + case DXGI_FORMAT_R16_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X16_TYPELESS_G8_UINT: + return 24; +#endif + +#endif // _XBOX_ONE && _TITLE + default: return 0; } @@ -375,8 +412,9 @@ static void GetSurfaceInfo( _In_ size_t width, size_t numRows = 0; bool bc = false; - bool packed = false; - size_t bcnumBytesPerBlock = 0; + bool packed = false; + bool planar = false; + size_t bpe = 0; switch (fmt) { case DXGI_FORMAT_BC1_TYPELESS: @@ -386,7 +424,7 @@ static void GetSurfaceInfo( _In_ size_t width, case DXGI_FORMAT_BC4_UNORM: case DXGI_FORMAT_BC4_SNORM: bc=true; - bcnumBytesPerBlock = 8; + bpe = 8; break; case DXGI_FORMAT_BC2_TYPELESS: @@ -405,13 +443,44 @@ static void GetSurfaceInfo( _In_ size_t width, case DXGI_FORMAT_BC7_UNORM: case DXGI_FORMAT_BC7_UNORM_SRGB: bc = true; - bcnumBytesPerBlock = 16; + bpe = 16; break; case DXGI_FORMAT_R8G8_B8G8_UNORM: case DXGI_FORMAT_G8R8_G8B8_UNORM: + case DXGI_FORMAT_YUY2: packed = true; + bpe = 4; break; + + case DXGI_FORMAT_Y210: + case DXGI_FORMAT_Y216: + packed = true; + bpe = 8; + break; + + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_420_OPAQUE: + planar = true; + bpe = 2; + break; + + case DXGI_FORMAT_P010: + case DXGI_FORMAT_P016: + planar = true; + bpe = 4; + break; + +#if defined(_XBOX_ONE) && defined(_TITLE) && MONOLITHIC + + case DXGI_FORMAT_D16_UNORM_S8_UINT: + case DXGI_FORMAT_R16_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X16_TYPELESS_G8_UINT: + planar = true; + bpe = 4; + break; + +#endif } if (bc) @@ -426,22 +495,36 @@ static void GetSurfaceInfo( _In_ size_t width, { numBlocksHigh = std::max( 1, (height + 3) / 4 ); } - rowBytes = numBlocksWide * bcnumBytesPerBlock; + rowBytes = numBlocksWide * bpe; numRows = numBlocksHigh; + numBytes = rowBytes * numBlocksHigh; } else if (packed) { - rowBytes = ( ( width + 1 ) >> 1 ) * 4; + rowBytes = ( ( width + 1 ) >> 1 ) * bpe; numRows = height; + numBytes = rowBytes * height; + } + else if ( fmt == DXGI_FORMAT_NV11 ) + { + rowBytes = ( ( width + 1 ) >> 1 ) * 2; + numBytes = rowBytes * ( ( height + 1 ) >> 1 ) * 4; + numRows = height * 2; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data + } + else if (planar) + { + rowBytes = ( ( width + 1 ) >> 1 ) * bpe; + numBytes = ( rowBytes * height ) + ( ( rowBytes * height + 1 ) >> 1 ); + numRows = height + ( ( height + 1 ) >> 1 ); } else { size_t bpp = BitsPerPixel( fmt ); rowBytes = ( width * bpp + 7 ) / 8; // round up to nearest byte numRows = height; + numBytes = rowBytes * height; } - numBytes = rowBytes * numRows; if (outNumBytes) { *outNumBytes = numBytes; @@ -710,7 +793,8 @@ HRESULT DirectX::SaveDDSTextureToFile( _In_ ID3D11DeviceContext* pContext, case DXGI_FORMAT_B5G5R5A1_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_A1R5G5B5, sizeof(DDS_PIXELFORMAT) ); break; case DXGI_FORMAT_B8G8R8A8_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_A8R8G8B8, sizeof(DDS_PIXELFORMAT) ); break; // DXGI 1.1 case DXGI_FORMAT_B8G8R8X8_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_X8R8G8B8, sizeof(DDS_PIXELFORMAT) ); break; // DXGI 1.1 - case DXGI_FORMAT_B4G4R4A4_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_A4R4G4B4, sizeof(DDS_PIXELFORMAT) ); break; + case DXGI_FORMAT_YUY2: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_YUY2, sizeof(DDS_PIXELFORMAT) ); break; // DXGI 1.2 + case DXGI_FORMAT_B4G4R4A4_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_A4R4G4B4, sizeof(DDS_PIXELFORMAT) ); break; // DXGI 1.2 // Legacy D3DX formats using D3DFMT enum value as FourCC case DXGI_FORMAT_R32G32B32A32_FLOAT: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 116; break; // D3DFMT_A32B32G32R32F @@ -722,6 +806,12 @@ HRESULT DirectX::SaveDDSTextureToFile( _In_ ID3D11DeviceContext* pContext, case DXGI_FORMAT_R32_FLOAT: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 114; break; // D3DFMT_R32F case DXGI_FORMAT_R16_FLOAT: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 111; break; // D3DFMT_R16F + case DXGI_FORMAT_AI44: + case DXGI_FORMAT_IA44: + case DXGI_FORMAT_P8: + case DXGI_FORMAT_A8P8: + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + default: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_DX10, sizeof(DDS_PIXELFORMAT) ); @@ -767,9 +857,9 @@ HRESULT DirectX::SaveDDSTextureToFile( _In_ ID3D11DeviceContext* pContext, uint8_t* dptr = pixels.get(); + size_t msize = std::min( rowPitch, mapped.RowPitch ); for( size_t h = 0; h < rowCount; ++h ) { - size_t msize = std::min( rowPitch, mapped.RowPitch ); memcpy_s( dptr, rowPitch, sptr, msize ); sptr += mapped.RowPitch; dptr += rowPitch;