diff --git a/DDSTextureLoader/DDSTextureLoader12.cpp b/DDSTextureLoader/DDSTextureLoader12.cpp index 851233d..62b8ac6 100644 --- a/DDSTextureLoader/DDSTextureLoader12.cpp +++ b/DDSTextureLoader/DDSTextureLoader12.cpp @@ -165,21 +165,11 @@ namespace } // open the file -#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) ScopedHandle hFile( safe_handle( CreateFile2( fileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr ) ) ); -#else - ScopedHandle hFile( safe_handle( CreateFileW( fileName, - GENERIC_READ, - FILE_SHARE_READ, - nullptr, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - nullptr ) ) ); -#endif if ( !hFile ) { diff --git a/DirectXTex/BC.cpp b/DirectXTex/BC.cpp index d8b32cc..4924354 100644 --- a/DirectXTex/BC.cpp +++ b/DirectXTex/BC.cpp @@ -21,600 +21,412 @@ #include "BC.h" +using namespace DirectX; using namespace DirectX::PackedVector; -namespace DirectX +namespace { + //------------------------------------------------------------------------------------- + // Constants + //------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------- -// Constants -//------------------------------------------------------------------------------------- + // Perceptual weightings for the importance of each channel. + const HDRColorA g_Luminance(0.2125f / 0.7154f, 1.0f, 0.0721f / 0.7154f, 1.0f); + const HDRColorA g_LuminanceInv(0.7154f / 0.2125f, 1.0f, 0.7154f / 0.0721f, 1.0f); -// Perceptual weightings for the importance of each channel. -static const HDRColorA g_Luminance (0.2125f / 0.7154f, 1.0f, 0.0721f / 0.7154f, 1.0f); -static const HDRColorA g_LuminanceInv(0.7154f / 0.2125f, 1.0f, 0.7154f / 0.0721f, 1.0f); - -//------------------------------------------------------------------------------------- -// Decode/Encode RGB 5/6/5 colors -//------------------------------------------------------------------------------------- -inline static void Decode565(_Out_ HDRColorA *pColor, _In_ const uint16_t w565) -{ - pColor->r = (float) ((w565 >> 11) & 31) * (1.0f / 31.0f); - pColor->g = (float) ((w565 >> 5) & 63) * (1.0f / 63.0f); - pColor->b = (float) ((w565 >> 0) & 31) * (1.0f / 31.0f); - pColor->a = 1.0f; -} - -inline static uint16_t Encode565(_In_ const HDRColorA *pColor) -{ - HDRColorA Color; - - Color.r = (pColor->r < 0.0f) ? 0.0f : (pColor->r > 1.0f) ? 1.0f : pColor->r; - Color.g = (pColor->g < 0.0f) ? 0.0f : (pColor->g > 1.0f) ? 1.0f : pColor->g; - Color.b = (pColor->b < 0.0f) ? 0.0f : (pColor->b > 1.0f) ? 1.0f : pColor->b; - - uint16_t w; - - w = (uint16_t) ((static_cast(Color.r * 31.0f + 0.5f) << 11) | - (static_cast(Color.g * 63.0f + 0.5f) << 5) | - (static_cast(Color.b * 31.0f + 0.5f) << 0)); - - return w; -} - - -//------------------------------------------------------------------------------------- -static void OptimizeRGB(_Out_ HDRColorA *pX, _Out_ HDRColorA *pY, - _In_reads_(NUM_PIXELS_PER_BLOCK) const HDRColorA *pPoints, _In_ size_t cSteps, _In_ DWORD flags) -{ - static const float fEpsilon = (0.25f / 64.0f) * (0.25f / 64.0f); - static const float pC3[] = { 2.0f/2.0f, 1.0f/2.0f, 0.0f/2.0f }; - static const float pD3[] = { 0.0f/2.0f, 1.0f/2.0f, 2.0f/2.0f }; - static const float pC4[] = { 3.0f/3.0f, 2.0f/3.0f, 1.0f/3.0f, 0.0f/3.0f }; - static const float pD4[] = { 0.0f/3.0f, 1.0f/3.0f, 2.0f/3.0f, 3.0f/3.0f }; - - const float *pC = (3 == cSteps) ? pC3 : pC4; - const float *pD = (3 == cSteps) ? pD3 : pD4; - - // Find Min and Max points, as starting point - HDRColorA X = (flags & BC_FLAGS_UNIFORM) ? HDRColorA(1.f, 1.f, 1.f, 1.f) : g_Luminance; - HDRColorA Y = HDRColorA(0.0f, 0.0f, 0.0f, 1.0f); - - for(size_t iPoint = 0; iPoint < NUM_PIXELS_PER_BLOCK; iPoint++) + //------------------------------------------------------------------------------------- + // Decode/Encode RGB 5/6/5 colors + //------------------------------------------------------------------------------------- + inline void Decode565(_Out_ HDRColorA *pColor, _In_ const uint16_t w565) { + pColor->r = (float)((w565 >> 11) & 31) * (1.0f / 31.0f); + pColor->g = (float)((w565 >> 5) & 63) * (1.0f / 63.0f); + pColor->b = (float)((w565 >> 0) & 31) * (1.0f / 31.0f); + pColor->a = 1.0f; + } + + inline uint16_t Encode565(_In_ const HDRColorA *pColor) + { + HDRColorA Color; + + Color.r = (pColor->r < 0.0f) ? 0.0f : (pColor->r > 1.0f) ? 1.0f : pColor->r; + Color.g = (pColor->g < 0.0f) ? 0.0f : (pColor->g > 1.0f) ? 1.0f : pColor->g; + Color.b = (pColor->b < 0.0f) ? 0.0f : (pColor->b > 1.0f) ? 1.0f : pColor->b; + + uint16_t w; + + w = (uint16_t)((static_cast(Color.r * 31.0f + 0.5f) << 11) | + (static_cast(Color.g * 63.0f + 0.5f) << 5) | + (static_cast(Color.b * 31.0f + 0.5f) << 0)); + + return w; + } + + + //------------------------------------------------------------------------------------- + void OptimizeRGB( + _Out_ HDRColorA *pX, + _Out_ HDRColorA *pY, + _In_reads_(NUM_PIXELS_PER_BLOCK) const HDRColorA *pPoints, + size_t cSteps, + DWORD flags) + { + static const float fEpsilon = (0.25f / 64.0f) * (0.25f / 64.0f); + static const float pC3[] = { 2.0f / 2.0f, 1.0f / 2.0f, 0.0f / 2.0f }; + static const float pD3[] = { 0.0f / 2.0f, 1.0f / 2.0f, 2.0f / 2.0f }; + static const float pC4[] = { 3.0f / 3.0f, 2.0f / 3.0f, 1.0f / 3.0f, 0.0f / 3.0f }; + static const float pD4[] = { 0.0f / 3.0f, 1.0f / 3.0f, 2.0f / 3.0f, 3.0f / 3.0f }; + + const float *pC = (3 == cSteps) ? pC3 : pC4; + const float *pD = (3 == cSteps) ? pD3 : pD4; + + // Find Min and Max points, as starting point + HDRColorA X = (flags & BC_FLAGS_UNIFORM) ? HDRColorA(1.f, 1.f, 1.f, 1.f) : g_Luminance; + HDRColorA Y = HDRColorA(0.0f, 0.0f, 0.0f, 1.0f); + + for (size_t iPoint = 0; iPoint < NUM_PIXELS_PER_BLOCK; iPoint++) + { #ifdef COLOR_WEIGHTS - if(pPoints[iPoint].a > 0.0f) + if (pPoints[iPoint].a > 0.0f) #endif // COLOR_WEIGHTS - { - if(pPoints[iPoint].r < X.r) - X.r = pPoints[iPoint].r; + { + if (pPoints[iPoint].r < X.r) + X.r = pPoints[iPoint].r; - if(pPoints[iPoint].g < X.g) - X.g = pPoints[iPoint].g; + if (pPoints[iPoint].g < X.g) + X.g = pPoints[iPoint].g; - if(pPoints[iPoint].b < X.b) - X.b = pPoints[iPoint].b; + if (pPoints[iPoint].b < X.b) + X.b = pPoints[iPoint].b; - if(pPoints[iPoint].r > Y.r) - Y.r = pPoints[iPoint].r; + if (pPoints[iPoint].r > Y.r) + Y.r = pPoints[iPoint].r; - if(pPoints[iPoint].g > Y.g) - Y.g = pPoints[iPoint].g; + if (pPoints[iPoint].g > Y.g) + Y.g = pPoints[iPoint].g; - if(pPoints[iPoint].b > Y.b) - Y.b = pPoints[iPoint].b; - } - } - - // Diagonal axis - HDRColorA AB; - - AB.r = Y.r - X.r; - AB.g = Y.g - X.g; - AB.b = Y.b - X.b; - - float fAB = AB.r * AB.r + AB.g * AB.g + AB.b * AB.b; - - // Single color block.. no need to root-find - if(fAB < FLT_MIN) - { - pX->r = X.r; pX->g = X.g; pX->b = X.b; - pY->r = Y.r; pY->g = Y.g; pY->b = Y.b; - return; - } - - // Try all four axis directions, to determine which diagonal best fits data - float fABInv = 1.0f / fAB; - - HDRColorA Dir; - Dir.r = AB.r * fABInv; - Dir.g = AB.g * fABInv; - Dir.b = AB.b * fABInv; - - HDRColorA Mid; - Mid.r = (X.r + Y.r) * 0.5f; - Mid.g = (X.g + Y.g) * 0.5f; - Mid.b = (X.b + Y.b) * 0.5f; - - float fDir[4]; - fDir[0] = fDir[1] = fDir[2] = fDir[3] = 0.0f; - - - for(size_t iPoint = 0; iPoint < NUM_PIXELS_PER_BLOCK; iPoint++) - { - HDRColorA Pt; - Pt.r = (pPoints[iPoint].r - Mid.r) * Dir.r; - Pt.g = (pPoints[iPoint].g - Mid.g) * Dir.g; - Pt.b = (pPoints[iPoint].b - Mid.b) * Dir.b; - - float f; - -#ifdef COLOR_WEIGHTS - f = Pt.r + Pt.g + Pt.b; - fDir[0] += pPoints[iPoint].a * f * f; - - f = Pt.r + Pt.g - Pt.b; - fDir[1] += pPoints[iPoint].a * f * f; - - f = Pt.r - Pt.g + Pt.b; - fDir[2] += pPoints[iPoint].a * f * f; - - f = Pt.r - Pt.g - Pt.b; - fDir[3] += pPoints[iPoint].a * f * f; -#else - f = Pt.r + Pt.g + Pt.b; - fDir[0] += f * f; - - f = Pt.r + Pt.g - Pt.b; - fDir[1] += f * f; - - f = Pt.r - Pt.g + Pt.b; - fDir[2] += f * f; - - f = Pt.r - Pt.g - Pt.b; - fDir[3] += f * f; -#endif // COLOR_WEIGHTS - } - - float fDirMax = fDir[0]; - size_t iDirMax = 0; - - for(size_t iDir = 1; iDir < 4; iDir++) - { - if(fDir[iDir] > fDirMax) - { - fDirMax = fDir[iDir]; - iDirMax = iDir; - } - } - - if(iDirMax & 2) - { - float f = X.g; X.g = Y.g; Y.g = f; - } - - if(iDirMax & 1) - { - float f = X.b; X.b = Y.b; Y.b = f; - } - - - // Two color block.. no need to root-find - if(fAB < 1.0f / 4096.0f) - { - pX->r = X.r; pX->g = X.g; pX->b = X.b; - pY->r = Y.r; pY->g = Y.g; pY->b = Y.b; - return; - } - - - // Use Newton's Method to find local minima of sum-of-squares error. - float fSteps = (float) (cSteps - 1); - - for(size_t iIteration = 0; iIteration < 8; iIteration++) - { - // Calculate new steps - HDRColorA pSteps[4]; - - for(size_t iStep = 0; iStep < cSteps; iStep++) - { - pSteps[iStep].r = X.r * pC[iStep] + Y.r * pD[iStep]; - pSteps[iStep].g = X.g * pC[iStep] + Y.g * pD[iStep]; - pSteps[iStep].b = X.b * pC[iStep] + Y.b * pD[iStep]; + if (pPoints[iPoint].b > Y.b) + Y.b = pPoints[iPoint].b; + } } + // Diagonal axis + HDRColorA AB; - // Calculate color direction - Dir.r = Y.r - X.r; - Dir.g = Y.g - X.g; - Dir.b = Y.b - X.b; + AB.r = Y.r - X.r; + AB.g = Y.g - X.g; + AB.b = Y.b - X.b; - float fLen = (Dir.r * Dir.r + Dir.g * Dir.g + Dir.b * Dir.b); + float fAB = AB.r * AB.r + AB.g * AB.g + AB.b * AB.b; - if(fLen < (1.0f / 4096.0f)) - break; - - float fScale = fSteps / fLen; - - Dir.r *= fScale; - Dir.g *= fScale; - Dir.b *= fScale; - - - // Evaluate function, and derivatives - float d2X, d2Y; - HDRColorA dX, dY; - d2X = d2Y = dX.r = dX.g = dX.b = dY.r = dY.g = dY.b = 0.0f; - - for(size_t iPoint = 0; iPoint < NUM_PIXELS_PER_BLOCK; iPoint++) + // Single color block.. no need to root-find + if (fAB < FLT_MIN) { - float fDot = (pPoints[iPoint].r - X.r) * Dir.r + - (pPoints[iPoint].g - X.g) * Dir.g + - (pPoints[iPoint].b - X.b) * Dir.b; - - - size_t iStep; - if(fDot <= 0.0f) - iStep = 0; - else if(fDot >= fSteps) - iStep = cSteps - 1; - else - iStep = static_cast(fDot + 0.5f); - - - HDRColorA Diff; - Diff.r = pSteps[iStep].r - pPoints[iPoint].r; - Diff.g = pSteps[iStep].g - pPoints[iPoint].g; - Diff.b = pSteps[iStep].b - pPoints[iPoint].b; - -#ifdef COLOR_WEIGHTS - float fC = pC[iStep] * pPoints[iPoint].a * (1.0f / 8.0f); - float fD = pD[iStep] * pPoints[iPoint].a * (1.0f / 8.0f); -#else - float fC = pC[iStep] * (1.0f / 8.0f); - float fD = pD[iStep] * (1.0f / 8.0f); -#endif // COLOR_WEIGHTS - - d2X += fC * pC[iStep]; - dX.r += fC * Diff.r; - dX.g += fC * Diff.g; - dX.b += fC * Diff.b; - - d2Y += fD * pD[iStep]; - dY.r += fD * Diff.r; - dY.g += fD * Diff.g; - dY.b += fD * Diff.b; - } - - - // Move endpoints - if(d2X > 0.0f) - { - float f = -1.0f / d2X; - - X.r += dX.r * f; - X.g += dX.g * f; - X.b += dX.b * f; - } - - if(d2Y > 0.0f) - { - float f = -1.0f / d2Y; - - Y.r += dY.r * f; - Y.g += dY.g * f; - Y.b += dY.b * f; - } - - if((dX.r * dX.r < fEpsilon) && (dX.g * dX.g < fEpsilon) && (dX.b * dX.b < fEpsilon) && - (dY.r * dY.r < fEpsilon) && (dY.g * dY.g < fEpsilon) && (dY.b * dY.b < fEpsilon)) - { - break; - } - } - - pX->r = X.r; pX->g = X.g; pX->b = X.b; - pY->r = Y.r; pY->g = Y.g; pY->b = Y.b; -} - - -//------------------------------------------------------------------------------------- -inline static void DecodeBC1( _Out_writes_(NUM_PIXELS_PER_BLOCK) XMVECTOR *pColor, _In_ const D3DX_BC1 *pBC, _In_ bool isbc1 ) -{ - assert( pColor && pBC ); - static_assert( sizeof(D3DX_BC1) == 8, "D3DX_BC1 should be 8 bytes" ); - - static XMVECTORF32 s_Scale = { 1.f/31.f, 1.f/63.f, 1.f/31.f, 1.f }; - - XMVECTOR clr0 = XMLoadU565( reinterpret_cast(&pBC->rgb[0]) ); - XMVECTOR clr1 = XMLoadU565( reinterpret_cast(&pBC->rgb[1]) ); - - clr0 = XMVectorMultiply( clr0, s_Scale ); - clr1 = XMVectorMultiply( clr1, s_Scale ); - - clr0 = XMVectorSwizzle<2, 1, 0, 3>( clr0 ); - clr1 = XMVectorSwizzle<2, 1, 0, 3>( clr1 ); - - clr0 = XMVectorSelect( g_XMIdentityR3, clr0, g_XMSelect1110 ); - clr1 = XMVectorSelect( g_XMIdentityR3, clr1, g_XMSelect1110 ); - - XMVECTOR clr2, clr3; - if ( isbc1 && (pBC->rgb[0] <= pBC->rgb[1]) ) - { - clr2 = XMVectorLerp( clr0, clr1, 0.5f ); - clr3 = XMVectorZero(); // Alpha of 0 - } - else - { - clr2 = XMVectorLerp( clr0, clr1, 1.f/3.f ); - clr3 = XMVectorLerp( clr0, clr1, 2.f/3.f ); - } - - uint32_t dw = pBC->bitmap; - - for(size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i, dw >>= 2) - { - switch(dw & 3) - { - case 0: pColor[i] = clr0; break; - case 1: pColor[i] = clr1; break; - case 2: pColor[i] = clr2; break; - - case 3: - default: pColor[i] = clr3; break; - } - } -} - - -//------------------------------------------------------------------------------------- - -static void EncodeBC1(_Out_ D3DX_BC1 *pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) const HDRColorA *pColor, - _In_ bool bColorKey, _In_ float alphaRef, _In_ DWORD flags) -{ - assert( pBC && pColor ); - static_assert( sizeof(D3DX_BC1) == 8, "D3DX_BC1 should be 8 bytes" ); - - // Determine if we need to colorkey this block - size_t uSteps; - - if (bColorKey) - { - size_t uColorKey = 0; - - for(size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) - { - if(pColor[i].a < alphaRef) - uColorKey++; - } - - if(NUM_PIXELS_PER_BLOCK == uColorKey) - { - pBC->rgb[0] = 0x0000; - pBC->rgb[1] = 0xffff; - pBC->bitmap = 0xffffffff; + pX->r = X.r; pX->g = X.g; pX->b = X.b; + pY->r = Y.r; pY->g = Y.g; pY->b = Y.b; return; } - uSteps = (uColorKey > 0) ? 3 : 4; - } - else - { - uSteps = 4; - } + // Try all four axis directions, to determine which diagonal best fits data + float fABInv = 1.0f / fAB; - // Quantize block to R56B5, using Floyd Stienberg error diffusion. This - // increases the chance that colors will map directly to the quantized - // axis endpoints. - HDRColorA Color[NUM_PIXELS_PER_BLOCK]; - HDRColorA Error[NUM_PIXELS_PER_BLOCK]; + HDRColorA Dir; + Dir.r = AB.r * fABInv; + Dir.g = AB.g * fABInv; + Dir.b = AB.b * fABInv; - if (flags & BC_FLAGS_DITHER_RGB) - memset(Error, 0x00, NUM_PIXELS_PER_BLOCK * sizeof(HDRColorA)); + HDRColorA Mid; + Mid.r = (X.r + Y.r) * 0.5f; + Mid.g = (X.g + Y.g) * 0.5f; + Mid.b = (X.b + Y.b) * 0.5f; - size_t i; - for(i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) - { - HDRColorA Clr; - Clr.r = pColor[i].r; - Clr.g = pColor[i].g; - Clr.b = pColor[i].b; + float fDir[4]; + fDir[0] = fDir[1] = fDir[2] = fDir[3] = 0.0f; - if (flags & BC_FLAGS_DITHER_RGB) + + for (size_t iPoint = 0; iPoint < NUM_PIXELS_PER_BLOCK; iPoint++) { - Clr.r += Error[i].r; - Clr.g += Error[i].g; - Clr.b += Error[i].b; - } + HDRColorA Pt; + Pt.r = (pPoints[iPoint].r - Mid.r) * Dir.r; + Pt.g = (pPoints[iPoint].g - Mid.g) * Dir.g; + Pt.b = (pPoints[iPoint].b - Mid.b) * Dir.b; - Color[i].r = (float) static_cast(Clr.r * 31.0f + 0.5f) * (1.0f / 31.0f); - Color[i].g = (float) static_cast(Clr.g * 63.0f + 0.5f) * (1.0f / 63.0f); - Color[i].b = (float) static_cast(Clr.b * 31.0f + 0.5f) * (1.0f / 31.0f); + float f; #ifdef COLOR_WEIGHTS - Color[i].a = pColor[i].a; + f = Pt.r + Pt.g + Pt.b; + fDir[0] += pPoints[iPoint].a * f * f; + + f = Pt.r + Pt.g - Pt.b; + fDir[1] += pPoints[iPoint].a * f * f; + + f = Pt.r - Pt.g + Pt.b; + fDir[2] += pPoints[iPoint].a * f * f; + + f = Pt.r - Pt.g - Pt.b; + fDir[3] += pPoints[iPoint].a * f * f; #else - Color[i].a = 1.0f; + f = Pt.r + Pt.g + Pt.b; + fDir[0] += f * f; + + f = Pt.r + Pt.g - Pt.b; + fDir[1] += f * f; + + f = Pt.r - Pt.g + Pt.b; + fDir[2] += f * f; + + f = Pt.r - Pt.g - Pt.b; + fDir[3] += f * f; +#endif // COLOR_WEIGHTS + } + + float fDirMax = fDir[0]; + size_t iDirMax = 0; + + for (size_t iDir = 1; iDir < 4; iDir++) + { + if (fDir[iDir] > fDirMax) + { + fDirMax = fDir[iDir]; + iDirMax = iDir; + } + } + + if (iDirMax & 2) + { + float f = X.g; X.g = Y.g; Y.g = f; + } + + if (iDirMax & 1) + { + float f = X.b; X.b = Y.b; Y.b = f; + } + + + // Two color block.. no need to root-find + if (fAB < 1.0f / 4096.0f) + { + pX->r = X.r; pX->g = X.g; pX->b = X.b; + pY->r = Y.r; pY->g = Y.g; pY->b = Y.b; + return; + } + + // Use Newton's Method to find local minima of sum-of-squares error. + float fSteps = (float)(cSteps - 1); + + for (size_t iIteration = 0; iIteration < 8; iIteration++) + { + // Calculate new steps + HDRColorA pSteps[4]; + + for (size_t iStep = 0; iStep < cSteps; iStep++) + { + pSteps[iStep].r = X.r * pC[iStep] + Y.r * pD[iStep]; + pSteps[iStep].g = X.g * pC[iStep] + Y.g * pD[iStep]; + pSteps[iStep].b = X.b * pC[iStep] + Y.b * pD[iStep]; + } + + + // Calculate color direction + Dir.r = Y.r - X.r; + Dir.g = Y.g - X.g; + Dir.b = Y.b - X.b; + + float fLen = (Dir.r * Dir.r + Dir.g * Dir.g + Dir.b * Dir.b); + + if (fLen < (1.0f / 4096.0f)) + break; + + float fScale = fSteps / fLen; + + Dir.r *= fScale; + Dir.g *= fScale; + Dir.b *= fScale; + + + // Evaluate function, and derivatives + float d2X, d2Y; + HDRColorA dX, dY; + d2X = d2Y = dX.r = dX.g = dX.b = dY.r = dY.g = dY.b = 0.0f; + + for (size_t iPoint = 0; iPoint < NUM_PIXELS_PER_BLOCK; iPoint++) + { + float fDot = (pPoints[iPoint].r - X.r) * Dir.r + + (pPoints[iPoint].g - X.g) * Dir.g + + (pPoints[iPoint].b - X.b) * Dir.b; + + + size_t iStep; + if (fDot <= 0.0f) + iStep = 0; + else if (fDot >= fSteps) + iStep = cSteps - 1; + else + iStep = static_cast(fDot + 0.5f); + + + HDRColorA Diff; + Diff.r = pSteps[iStep].r - pPoints[iPoint].r; + Diff.g = pSteps[iStep].g - pPoints[iPoint].g; + Diff.b = pSteps[iStep].b - pPoints[iPoint].b; + +#ifdef COLOR_WEIGHTS + float fC = pC[iStep] * pPoints[iPoint].a * (1.0f / 8.0f); + float fD = pD[iStep] * pPoints[iPoint].a * (1.0f / 8.0f); +#else + float fC = pC[iStep] * (1.0f / 8.0f); + float fD = pD[iStep] * (1.0f / 8.0f); #endif // COLOR_WEIGHTS - if (flags & BC_FLAGS_DITHER_RGB) - { - HDRColorA Diff; - Diff.r = Color[i].a * (Clr.r - Color[i].r); - Diff.g = Color[i].a * (Clr.g - Color[i].g); - Diff.b = Color[i].a * (Clr.b - Color[i].b); + d2X += fC * pC[iStep]; + dX.r += fC * Diff.r; + dX.g += fC * Diff.g; + dX.b += fC * Diff.b; - if(3 != (i & 3)) - { - assert( i < 15 ); - _Analysis_assume_( i < 15 ); - Error[i + 1].r += Diff.r * (7.0f / 16.0f); - Error[i + 1].g += Diff.g * (7.0f / 16.0f); - Error[i + 1].b += Diff.b * (7.0f / 16.0f); + d2Y += fD * pD[iStep]; + dY.r += fD * Diff.r; + dY.g += fD * Diff.g; + dY.b += fD * Diff.b; } - if(i < 12) + // Move endpoints + if (d2X > 0.0f) { - if(i & 3) - { - Error[i + 3].r += Diff.r * (3.0f / 16.0f); - Error[i + 3].g += Diff.g * (3.0f / 16.0f); - Error[i + 3].b += Diff.b * (3.0f / 16.0f); - } + float f = -1.0f / d2X; - Error[i + 4].r += Diff.r * (5.0f / 16.0f); - Error[i + 4].g += Diff.g * (5.0f / 16.0f); - Error[i + 4].b += Diff.b * (5.0f / 16.0f); + X.r += dX.r * f; + X.g += dX.g * f; + X.b += dX.b * f; + } - if(3 != (i & 3)) - { - assert( i < 11 ); - _Analysis_assume_( i < 11 ); - Error[i + 5].r += Diff.r * (1.0f / 16.0f); - Error[i + 5].g += Diff.g * (1.0f / 16.0f); - Error[i + 5].b += Diff.b * (1.0f / 16.0f); - } + if (d2Y > 0.0f) + { + float f = -1.0f / d2Y; + + Y.r += dY.r * f; + Y.g += dY.g * f; + Y.b += dY.b * f; + } + + if ((dX.r * dX.r < fEpsilon) && (dX.g * dX.g < fEpsilon) && (dX.b * dX.b < fEpsilon) && + (dY.r * dY.r < fEpsilon) && (dY.g * dY.g < fEpsilon) && (dY.b * dY.b < fEpsilon)) + { + break; } } - if ( !( flags & BC_FLAGS_UNIFORM ) ) + pX->r = X.r; pX->g = X.g; pX->b = X.b; + pY->r = Y.r; pY->g = Y.g; pY->b = Y.b; + } + + + //------------------------------------------------------------------------------------- + inline void DecodeBC1( + _Out_writes_(NUM_PIXELS_PER_BLOCK) XMVECTOR *pColor, + _In_ const D3DX_BC1 *pBC, + bool isbc1) + { + assert(pColor && pBC); + static_assert(sizeof(D3DX_BC1) == 8, "D3DX_BC1 should be 8 bytes"); + + static XMVECTORF32 s_Scale = { 1.f / 31.f, 1.f / 63.f, 1.f / 31.f, 1.f }; + + XMVECTOR clr0 = XMLoadU565(reinterpret_cast(&pBC->rgb[0])); + XMVECTOR clr1 = XMLoadU565(reinterpret_cast(&pBC->rgb[1])); + + clr0 = XMVectorMultiply(clr0, s_Scale); + clr1 = XMVectorMultiply(clr1, s_Scale); + + clr0 = XMVectorSwizzle<2, 1, 0, 3>(clr0); + clr1 = XMVectorSwizzle<2, 1, 0, 3>(clr1); + + clr0 = XMVectorSelect(g_XMIdentityR3, clr0, g_XMSelect1110); + clr1 = XMVectorSelect(g_XMIdentityR3, clr1, g_XMSelect1110); + + XMVECTOR clr2, clr3; + if (isbc1 && (pBC->rgb[0] <= pBC->rgb[1])) { - Color[i].r *= g_Luminance.r; - Color[i].g *= g_Luminance.g; - Color[i].b *= g_Luminance.b; - } - } - - // Perform 6D root finding function to find two endpoints of color axis. - // Then quantize and sort the endpoints depending on mode. - HDRColorA ColorA, ColorB, ColorC, ColorD; - - OptimizeRGB(&ColorA, &ColorB, Color, uSteps, flags); - - if ( flags & BC_FLAGS_UNIFORM ) - { - ColorC = ColorA; - ColorD = ColorB; - } - else - { - ColorC.r = ColorA.r * g_LuminanceInv.r; - ColorC.g = ColorA.g * g_LuminanceInv.g; - ColorC.b = ColorA.b * g_LuminanceInv.b; - - ColorD.r = ColorB.r * g_LuminanceInv.r; - ColorD.g = ColorB.g * g_LuminanceInv.g; - ColorD.b = ColorB.b * g_LuminanceInv.b; - } - - uint16_t wColorA = Encode565(&ColorC); - uint16_t wColorB = Encode565(&ColorD); - - if((uSteps == 4) && (wColorA == wColorB)) - { - pBC->rgb[0] = wColorA; - pBC->rgb[1] = wColorB; - pBC->bitmap = 0x00000000; - return; - } - - Decode565(&ColorC, wColorA); - Decode565(&ColorD, wColorB); - - if ( flags & BC_FLAGS_UNIFORM ) - { - ColorA = ColorC; - ColorB = ColorD; - } - else - { - ColorA.r = ColorC.r * g_Luminance.r; - ColorA.g = ColorC.g * g_Luminance.g; - ColorA.b = ColorC.b * g_Luminance.b; - - ColorB.r = ColorD.r * g_Luminance.r; - ColorB.g = ColorD.g * g_Luminance.g; - ColorB.b = ColorD.b * g_Luminance.b; - } - - // Calculate color steps - HDRColorA Step[4]; - - if((3 == uSteps) == (wColorA <= wColorB)) - { - pBC->rgb[0] = wColorA; - pBC->rgb[1] = wColorB; - - Step[0] = ColorA; - Step[1] = ColorB; - } - else - { - pBC->rgb[0] = wColorB; - pBC->rgb[1] = wColorA; - - Step[0] = ColorB; - Step[1] = ColorA; - } - - static const size_t pSteps3[] = { 0, 2, 1 }; - static const size_t pSteps4[] = { 0, 2, 3, 1 }; - const size_t *pSteps; - - if(3 == uSteps) - { - pSteps = pSteps3; - - HDRColorALerp(&Step[2], &Step[0], &Step[1], 0.5f); - } - else - { - pSteps = pSteps4; - - HDRColorALerp(&Step[2], &Step[0], &Step[1], 1.0f / 3.0f); - HDRColorALerp(&Step[3], &Step[0], &Step[1], 2.0f / 3.0f); - } - - // Calculate color direction - HDRColorA Dir; - - Dir.r = Step[1].r - Step[0].r; - Dir.g = Step[1].g - Step[0].g; - Dir.b = Step[1].b - Step[0].b; - - float fSteps = (float) (uSteps - 1); - float fScale = (wColorA != wColorB) ? (fSteps / (Dir.r * Dir.r + Dir.g * Dir.g + Dir.b * Dir.b)) : 0.0f; - - Dir.r *= fScale; - Dir.g *= fScale; - Dir.b *= fScale; - - // Encode colors - uint32_t dw = 0; - if (flags & BC_FLAGS_DITHER_RGB) - memset(Error, 0x00, NUM_PIXELS_PER_BLOCK * sizeof(HDRColorA)); - - for(i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) - { - if((3 == uSteps) && (pColor[i].a < alphaRef)) - { - dw = (3 << 30) | (dw >> 2); + clr2 = XMVectorLerp(clr0, clr1, 0.5f); + clr3 = XMVectorZero(); // Alpha of 0 } else + { + clr2 = XMVectorLerp(clr0, clr1, 1.f / 3.f); + clr3 = XMVectorLerp(clr0, clr1, 2.f / 3.f); + } + + uint32_t dw = pBC->bitmap; + + for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i, dw >>= 2) + { + switch (dw & 3) + { + case 0: pColor[i] = clr0; break; + case 1: pColor[i] = clr1; break; + case 2: pColor[i] = clr2; break; + + case 3: + default: pColor[i] = clr3; break; + } + } + } + + + //------------------------------------------------------------------------------------- + void EncodeBC1( + _Out_ D3DX_BC1 *pBC, + _In_reads_(NUM_PIXELS_PER_BLOCK) const HDRColorA *pColor, + bool bColorKey, + float alphaRef, + DWORD flags) + { + assert(pBC && pColor); + static_assert(sizeof(D3DX_BC1) == 8, "D3DX_BC1 should be 8 bytes"); + + // Determine if we need to colorkey this block + size_t uSteps; + + if (bColorKey) + { + size_t uColorKey = 0; + + for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + { + if (pColor[i].a < alphaRef) + uColorKey++; + } + + if (NUM_PIXELS_PER_BLOCK == uColorKey) + { + pBC->rgb[0] = 0x0000; + pBC->rgb[1] = 0xffff; + pBC->bitmap = 0xffffffff; + return; + } + + uSteps = (uColorKey > 0) ? 3 : 4; + } + else + { + uSteps = 4; + } + + // Quantize block to R56B5, using Floyd Stienberg error diffusion. This + // increases the chance that colors will map directly to the quantized + // axis endpoints. + HDRColorA Color[NUM_PIXELS_PER_BLOCK]; + HDRColorA Error[NUM_PIXELS_PER_BLOCK]; + + if (flags & BC_FLAGS_DITHER_RGB) + memset(Error, 0x00, NUM_PIXELS_PER_BLOCK * sizeof(HDRColorA)); + + size_t i; + for (i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { HDRColorA Clr; - if ( flags & BC_FLAGS_UNIFORM ) - { - Clr.r = pColor[i].r; - Clr.g = pColor[i].g; - Clr.b = pColor[i].b; - } - else - { - Clr.r = pColor[i].r * g_Luminance.r; - Clr.g = pColor[i].g * g_Luminance.g; - Clr.b = pColor[i].b * g_Luminance.b; - } + Clr.r = pColor[i].r; + Clr.g = pColor[i].g; + Clr.b = pColor[i].b; if (flags & BC_FLAGS_DITHER_RGB) { @@ -623,35 +435,35 @@ static void EncodeBC1(_Out_ D3DX_BC1 *pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) cons Clr.b += Error[i].b; } - float fDot = (Clr.r - Step[0].r) * Dir.r + (Clr.g - Step[0].g) * Dir.g + (Clr.b - Step[0].b) * Dir.b; - uint32_t iStep; + Color[i].r = (float) static_cast(Clr.r * 31.0f + 0.5f) * (1.0f / 31.0f); + Color[i].g = (float) static_cast(Clr.g * 63.0f + 0.5f) * (1.0f / 63.0f); + Color[i].b = (float) static_cast(Clr.b * 31.0f + 0.5f) * (1.0f / 31.0f); - if(fDot <= 0.0f) - iStep = 0; - else if(fDot >= fSteps) - iStep = 1; - else - iStep = static_cast( pSteps[static_cast(fDot + 0.5f)] ); - - dw = (iStep << 30) | (dw >> 2); +#ifdef COLOR_WEIGHTS + Color[i].a = pColor[i].a; +#else + Color[i].a = 1.0f; +#endif // COLOR_WEIGHTS if (flags & BC_FLAGS_DITHER_RGB) { HDRColorA Diff; - Diff.r = Color[i].a * (Clr.r - Step[iStep].r); - Diff.g = Color[i].a * (Clr.g - Step[iStep].g); - Diff.b = Color[i].a * (Clr.b - Step[iStep].b); + Diff.r = Color[i].a * (Clr.r - Color[i].r); + Diff.g = Color[i].a * (Clr.g - Color[i].g); + Diff.b = Color[i].a * (Clr.b - Color[i].b); - if(3 != (i & 3)) + if (3 != (i & 3)) { + assert(i < 15); + _Analysis_assume_(i < 15); Error[i + 1].r += Diff.r * (7.0f / 16.0f); Error[i + 1].g += Diff.g * (7.0f / 16.0f); Error[i + 1].b += Diff.b * (7.0f / 16.0f); } - if(i < 12) + if (i < 12) { - if(i & 3) + if (i & 3) { Error[i + 3].r += Diff.r * (3.0f / 16.0f); Error[i + 3].g += Diff.g * (3.0f / 16.0f); @@ -662,53 +474,250 @@ static void EncodeBC1(_Out_ D3DX_BC1 *pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) cons Error[i + 4].g += Diff.g * (5.0f / 16.0f); Error[i + 4].b += Diff.b * (5.0f / 16.0f); - if(3 != (i & 3)) + if (3 != (i & 3)) { + assert(i < 11); + _Analysis_assume_(i < 11); Error[i + 5].r += Diff.r * (1.0f / 16.0f); Error[i + 5].g += Diff.g * (1.0f / 16.0f); Error[i + 5].b += Diff.b * (1.0f / 16.0f); } } } + + if (!(flags & BC_FLAGS_UNIFORM)) + { + Color[i].r *= g_Luminance.r; + Color[i].g *= g_Luminance.g; + Color[i].b *= g_Luminance.b; + } } + + // Perform 6D root finding function to find two endpoints of color axis. + // Then quantize and sort the endpoints depending on mode. + HDRColorA ColorA, ColorB, ColorC, ColorD; + + OptimizeRGB(&ColorA, &ColorB, Color, uSteps, flags); + + if (flags & BC_FLAGS_UNIFORM) + { + ColorC = ColorA; + ColorD = ColorB; + } + else + { + ColorC.r = ColorA.r * g_LuminanceInv.r; + ColorC.g = ColorA.g * g_LuminanceInv.g; + ColorC.b = ColorA.b * g_LuminanceInv.b; + + ColorD.r = ColorB.r * g_LuminanceInv.r; + ColorD.g = ColorB.g * g_LuminanceInv.g; + ColorD.b = ColorB.b * g_LuminanceInv.b; + } + + uint16_t wColorA = Encode565(&ColorC); + uint16_t wColorB = Encode565(&ColorD); + + if ((uSteps == 4) && (wColorA == wColorB)) + { + pBC->rgb[0] = wColorA; + pBC->rgb[1] = wColorB; + pBC->bitmap = 0x00000000; + return; + } + + Decode565(&ColorC, wColorA); + Decode565(&ColorD, wColorB); + + if (flags & BC_FLAGS_UNIFORM) + { + ColorA = ColorC; + ColorB = ColorD; + } + else + { + ColorA.r = ColorC.r * g_Luminance.r; + ColorA.g = ColorC.g * g_Luminance.g; + ColorA.b = ColorC.b * g_Luminance.b; + + ColorB.r = ColorD.r * g_Luminance.r; + ColorB.g = ColorD.g * g_Luminance.g; + ColorB.b = ColorD.b * g_Luminance.b; + } + + // Calculate color steps + HDRColorA Step[4]; + + if ((3 == uSteps) == (wColorA <= wColorB)) + { + pBC->rgb[0] = wColorA; + pBC->rgb[1] = wColorB; + + Step[0] = ColorA; + Step[1] = ColorB; + } + else + { + pBC->rgb[0] = wColorB; + pBC->rgb[1] = wColorA; + + Step[0] = ColorB; + Step[1] = ColorA; + } + + static const size_t pSteps3[] = { 0, 2, 1 }; + static const size_t pSteps4[] = { 0, 2, 3, 1 }; + const size_t *pSteps; + + if (3 == uSteps) + { + pSteps = pSteps3; + + HDRColorALerp(&Step[2], &Step[0], &Step[1], 0.5f); + } + else + { + pSteps = pSteps4; + + HDRColorALerp(&Step[2], &Step[0], &Step[1], 1.0f / 3.0f); + HDRColorALerp(&Step[3], &Step[0], &Step[1], 2.0f / 3.0f); + } + + // Calculate color direction + HDRColorA Dir; + + Dir.r = Step[1].r - Step[0].r; + Dir.g = Step[1].g - Step[0].g; + Dir.b = Step[1].b - Step[0].b; + + float fSteps = (float)(uSteps - 1); + float fScale = (wColorA != wColorB) ? (fSteps / (Dir.r * Dir.r + Dir.g * Dir.g + Dir.b * Dir.b)) : 0.0f; + + Dir.r *= fScale; + Dir.g *= fScale; + Dir.b *= fScale; + + // Encode colors + uint32_t dw = 0; + if (flags & BC_FLAGS_DITHER_RGB) + memset(Error, 0x00, NUM_PIXELS_PER_BLOCK * sizeof(HDRColorA)); + + for (i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + { + if ((3 == uSteps) && (pColor[i].a < alphaRef)) + { + dw = (3 << 30) | (dw >> 2); + } + else + { + HDRColorA Clr; + if (flags & BC_FLAGS_UNIFORM) + { + Clr.r = pColor[i].r; + Clr.g = pColor[i].g; + Clr.b = pColor[i].b; + } + else + { + Clr.r = pColor[i].r * g_Luminance.r; + Clr.g = pColor[i].g * g_Luminance.g; + Clr.b = pColor[i].b * g_Luminance.b; + } + + if (flags & BC_FLAGS_DITHER_RGB) + { + Clr.r += Error[i].r; + Clr.g += Error[i].g; + Clr.b += Error[i].b; + } + + float fDot = (Clr.r - Step[0].r) * Dir.r + (Clr.g - Step[0].g) * Dir.g + (Clr.b - Step[0].b) * Dir.b; + uint32_t iStep; + + if (fDot <= 0.0f) + iStep = 0; + else if (fDot >= fSteps) + iStep = 1; + else + iStep = static_cast(pSteps[static_cast(fDot + 0.5f)]); + + dw = (iStep << 30) | (dw >> 2); + + if (flags & BC_FLAGS_DITHER_RGB) + { + HDRColorA Diff; + Diff.r = Color[i].a * (Clr.r - Step[iStep].r); + Diff.g = Color[i].a * (Clr.g - Step[iStep].g); + Diff.b = Color[i].a * (Clr.b - Step[iStep].b); + + if (3 != (i & 3)) + { + Error[i + 1].r += Diff.r * (7.0f / 16.0f); + Error[i + 1].g += Diff.g * (7.0f / 16.0f); + Error[i + 1].b += Diff.b * (7.0f / 16.0f); + } + + if (i < 12) + { + if (i & 3) + { + Error[i + 3].r += Diff.r * (3.0f / 16.0f); + Error[i + 3].g += Diff.g * (3.0f / 16.0f); + Error[i + 3].b += Diff.b * (3.0f / 16.0f); + } + + Error[i + 4].r += Diff.r * (5.0f / 16.0f); + Error[i + 4].g += Diff.g * (5.0f / 16.0f); + Error[i + 4].b += Diff.b * (5.0f / 16.0f); + + if (3 != (i & 3)) + { + Error[i + 5].r += Diff.r * (1.0f / 16.0f); + Error[i + 5].g += Diff.g * (1.0f / 16.0f); + Error[i + 5].b += Diff.b * (1.0f / 16.0f); + } + } + } + } + } + + pBC->bitmap = dw; } - pBC->bitmap = dw; -} - -//------------------------------------------------------------------------------------- + //------------------------------------------------------------------------------------- #ifdef COLOR_WEIGHTS -static void EncodeSolidBC1(_Out_ D3DX_BC1 *pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) const HDRColorA *pColor) -{ -#ifdef COLOR_AVG_0WEIGHTS - // Compute avg color - HDRColorA Color; - Color.r = pColor[0].r; - Color.g = pColor[0].g; - Color.b = pColor[0].b; - - for(size_t i = 1; i < NUM_PIXELS_PER_BLOCK; ++i) + void EncodeSolidBC1(_Out_ D3DX_BC1 *pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) const HDRColorA *pColor) { - Color.r += pColor[i].r; - Color.g += pColor[i].g; - Color.b += pColor[i].b; - } +#ifdef COLOR_AVG_0WEIGHTS + // Compute avg color + HDRColorA Color; + Color.r = pColor[0].r; + Color.g = pColor[0].g; + Color.b = pColor[0].b; - Color.r *= 1.0f / 16.0f; - Color.g *= 1.0f / 16.0f; - Color.b *= 1.0f / 16.0f; + for (size_t i = 1; i < NUM_PIXELS_PER_BLOCK; ++i) + { + Color.r += pColor[i].r; + Color.g += pColor[i].g; + Color.b += pColor[i].b; + } - uint16_t wColor = Encode565(&Color); + Color.r *= 1.0f / 16.0f; + Color.g *= 1.0f / 16.0f; + Color.b *= 1.0f / 16.0f; + + uint16_t wColor = Encode565(&Color); #else - uint16_t wColor = 0x0000; + uint16_t wColor = 0x0000; #endif // COLOR_AVG_0WEIGHTS - // Encode solid block - pBC->rgb[0] = wColor; - pBC->rgb[1] = wColor; - pBC->bitmap = 0x00000000; -} + // Encode solid block + pBC->rgb[0] = wColor; + pBC->rgb[1] = wColor; + pBC->bitmap = 0x00000000; + } #endif // COLOR_WEIGHTS +} //===================================================================================== @@ -719,16 +728,16 @@ static void EncodeSolidBC1(_Out_ D3DX_BC1 *pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) // BC1 Compression //------------------------------------------------------------------------------------- _Use_decl_annotations_ -void D3DXDecodeBC1(XMVECTOR *pColor, const uint8_t *pBC) +void DirectX::D3DXDecodeBC1(XMVECTOR *pColor, const uint8_t *pBC) { auto pBC1 = reinterpret_cast(pBC); - DecodeBC1( pColor, pBC1, true ); + DecodeBC1(pColor, pBC1, true); } _Use_decl_annotations_ -void D3DXEncodeBC1(uint8_t *pBC, const XMVECTOR *pColor, float alphaRef, DWORD flags) +void DirectX::D3DXEncodeBC1(uint8_t *pBC, const XMVECTOR *pColor, float alphaRef, DWORD flags) { - assert( pBC && pColor ); + assert(pBC && pColor); HDRColorA Color[NUM_PIXELS_PER_BLOCK]; @@ -737,10 +746,10 @@ void D3DXEncodeBC1(uint8_t *pBC, const XMVECTOR *pColor, float alphaRef, DWORD f float fError[NUM_PIXELS_PER_BLOCK]; memset(fError, 0x00, NUM_PIXELS_PER_BLOCK * sizeof(float)); - for(size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { HDRColorA clr; - XMStoreFloat4( reinterpret_cast( &clr ), pColor[i] ); + XMStoreFloat4(reinterpret_cast(&clr), pColor[i]); float fAlph = clr.a + fError[i]; @@ -751,24 +760,24 @@ void D3DXEncodeBC1(uint8_t *pBC, const XMVECTOR *pColor, float alphaRef, DWORD f float fDiff = fAlph - Color[i].a; - if(3 != (i & 3)) + if (3 != (i & 3)) { - assert( i < 15 ); - _Analysis_assume_( i < 15 ); + assert(i < 15); + _Analysis_assume_(i < 15); fError[i + 1] += fDiff * (7.0f / 16.0f); } - if(i < 12) + if (i < 12) { - if(i & 3) + if (i & 3) fError[i + 3] += fDiff * (3.0f / 16.0f); fError[i + 4] += fDiff * (5.0f / 16.0f); - if(3 != (i & 3)) + if (3 != (i & 3)) { - assert( i < 11 ); - _Analysis_assume_( i < 11 ); + assert(i < 11); + _Analysis_assume_(i < 11); fError[i + 5] += fDiff * (1.0f / 16.0f); } } @@ -776,9 +785,9 @@ void D3DXEncodeBC1(uint8_t *pBC, const XMVECTOR *pColor, float alphaRef, DWORD f } else { - for(size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { - XMStoreFloat4( reinterpret_cast( &Color[i] ), pColor[i] ); + XMStoreFloat4(reinterpret_cast(&Color[i]), pColor[i]); } } @@ -791,10 +800,10 @@ void D3DXEncodeBC1(uint8_t *pBC, const XMVECTOR *pColor, float alphaRef, DWORD f // BC2 Compression //------------------------------------------------------------------------------------- _Use_decl_annotations_ -void D3DXDecodeBC2(XMVECTOR *pColor, const uint8_t *pBC) +void DirectX::D3DXDecodeBC2(XMVECTOR *pColor, const uint8_t *pBC) { - assert( pColor && pBC ); - static_assert( sizeof(D3DX_BC2) == 16, "D3DX_BC2 should be 16 bytes" ); + assert(pColor && pBC); + static_assert(sizeof(D3DX_BC2) == 16, "D3DX_BC2 should be 16 bytes"); auto pBC2 = reinterpret_cast(pBC); @@ -804,28 +813,28 @@ void D3DXDecodeBC2(XMVECTOR *pColor, const uint8_t *pBC) // 4-bit alpha part DWORD dw = pBC2->bitmap[0]; - for(size_t i = 0; i < 8; ++i, dw >>= 4) + for (size_t i = 0; i < 8; ++i, dw >>= 4) { - #pragma prefast(suppress:22103, "writing blocks in two halves confuses tool") - pColor[i] = XMVectorSetW( pColor[i], (float) (dw & 0xf) * (1.0f / 15.0f) ); +#pragma prefast(suppress:22103, "writing blocks in two halves confuses tool") + pColor[i] = XMVectorSetW(pColor[i], (float)(dw & 0xf) * (1.0f / 15.0f)); } dw = pBC2->bitmap[1]; - for(size_t i = 8; i < NUM_PIXELS_PER_BLOCK; ++i, dw >>= 4) - pColor[i] = XMVectorSetW( pColor[i], (float) (dw & 0xf) * (1.0f / 15.0f) ); + for (size_t i = 8; i < NUM_PIXELS_PER_BLOCK; ++i, dw >>= 4) + pColor[i] = XMVectorSetW(pColor[i], (float)(dw & 0xf) * (1.0f / 15.0f)); } _Use_decl_annotations_ -void D3DXEncodeBC2(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) +void DirectX::D3DXEncodeBC2(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) { - assert( pBC && pColor ); - static_assert( sizeof(D3DX_BC2) == 16, "D3DX_BC2 should be 16 bytes" ); + assert(pBC && pColor); + static_assert(sizeof(D3DX_BC2) == 16, "D3DX_BC2 should be 16 bytes"); HDRColorA Color[NUM_PIXELS_PER_BLOCK]; - for(size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { - XMStoreFloat4( reinterpret_cast( &Color[i] ), pColor[i] ); + XMStoreFloat4(reinterpret_cast(&Color[i]), pColor[i]); } auto pBC2 = reinterpret_cast(pBC); @@ -838,7 +847,7 @@ void D3DXEncodeBC2(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) if (flags & BC_FLAGS_DITHER_A) memset(fError, 0x00, NUM_PIXELS_PER_BLOCK * sizeof(float)); - for(size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { float fAlph = Color[i].a; if (flags & BC_FLAGS_DITHER_A) @@ -850,27 +859,27 @@ void D3DXEncodeBC2(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) pBC2->bitmap[i >> 3] |= (u << 28); if (flags & BC_FLAGS_DITHER_A) - { - float fDiff = fAlph - (float) u * (1.0f / 15.0f); + { + float fDiff = fAlph - (float)u * (1.0f / 15.0f); - if(3 != (i & 3)) + if (3 != (i & 3)) { - assert( i < 15 ); - _Analysis_assume_( i < 15 ); + assert(i < 15); + _Analysis_assume_(i < 15); fError[i + 1] += fDiff * (7.0f / 16.0f); } - if(i < 12) + if (i < 12) { - if(i & 3) + if (i & 3) fError[i + 3] += fDiff * (3.0f / 16.0f); fError[i + 4] += fDiff * (5.0f / 16.0f); - if(3 != (i & 3)) + if (3 != (i & 3)) { - assert( i < 11 ); - _Analysis_assume_( i < 11 ); + assert(i < 11); + _Analysis_assume_(i < 11); fError[i + 5] += fDiff * (1.0f / 16.0f); } } @@ -879,7 +888,7 @@ void D3DXEncodeBC2(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) // RGB part #ifdef COLOR_WEIGHTS - if(!pBC2->bitmap[0] && !pBC2->bitmap[1]) + if (!pBC2->bitmap[0] && !pBC2->bitmap[1]) { EncodeSolidBC1(pBC2->dxt1, Color); return; @@ -894,10 +903,10 @@ void D3DXEncodeBC2(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) // BC3 Compression //------------------------------------------------------------------------------------- _Use_decl_annotations_ -void D3DXDecodeBC3(XMVECTOR *pColor, const uint8_t *pBC) +void DirectX::D3DXDecodeBC3(XMVECTOR *pColor, const uint8_t *pBC) { - assert( pColor && pBC ); - static_assert( sizeof(D3DX_BC3) == 16, "D3DX_BC3 should be 16 bytes" ); + assert(pColor && pBC); + static_assert(sizeof(D3DX_BC3) == 16, "D3DX_BC3 should be 16 bytes"); auto pBC3 = reinterpret_cast(pBC); @@ -907,17 +916,17 @@ void D3DXDecodeBC3(XMVECTOR *pColor, const uint8_t *pBC) // Adaptive 3-bit alpha part float fAlpha[8]; - fAlpha[0] = ((float) pBC3->alpha[0]) * (1.0f / 255.0f); - fAlpha[1] = ((float) pBC3->alpha[1]) * (1.0f / 255.0f); + fAlpha[0] = ((float)pBC3->alpha[0]) * (1.0f / 255.0f); + fAlpha[1] = ((float)pBC3->alpha[1]) * (1.0f / 255.0f); - if(pBC3->alpha[0] > pBC3->alpha[1]) + if (pBC3->alpha[0] > pBC3->alpha[1]) { - for(size_t i = 1; i < 7; ++i) + for (size_t i = 1; i < 7; ++i) fAlpha[i + 1] = (fAlpha[0] * (7 - i) + fAlpha[1] * i) * (1.0f / 7.0f); } - else + else { - for(size_t i = 1; i < 5; ++i) + for (size_t i = 1; i < 5; ++i) fAlpha[i + 1] = (fAlpha[0] * (5 - i) + fAlpha[1] * i) * (1.0f / 5.0f); fAlpha[6] = 0.0f; @@ -926,25 +935,25 @@ void D3DXDecodeBC3(XMVECTOR *pColor, const uint8_t *pBC) DWORD dw = pBC3->bitmap[0] | (pBC3->bitmap[1] << 8) | (pBC3->bitmap[2] << 16); - for(size_t i = 0; i < 8; ++i, dw >>= 3) - pColor[i] = XMVectorSetW( pColor[i], fAlpha[dw & 0x7] ); + for (size_t i = 0; i < 8; ++i, dw >>= 3) + pColor[i] = XMVectorSetW(pColor[i], fAlpha[dw & 0x7]); dw = pBC3->bitmap[3] | (pBC3->bitmap[4] << 8) | (pBC3->bitmap[5] << 16); - for(size_t i = 8; i < NUM_PIXELS_PER_BLOCK; ++i, dw >>= 3) - pColor[i] = XMVectorSetW( pColor[i], fAlpha[dw & 0x7] ); + for (size_t i = 8; i < NUM_PIXELS_PER_BLOCK; ++i, dw >>= 3) + pColor[i] = XMVectorSetW(pColor[i], fAlpha[dw & 0x7]); } _Use_decl_annotations_ -void D3DXEncodeBC3(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) +void DirectX::D3DXEncodeBC3(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) { - assert( pBC && pColor ); - static_assert( sizeof(D3DX_BC3) == 16, "D3DX_BC3 should be 16 bytes" ); + assert(pBC && pColor); + static_assert(sizeof(D3DX_BC3) == 16, "D3DX_BC3 should be 16 bytes"); HDRColorA Color[NUM_PIXELS_PER_BLOCK]; - for(size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { - XMStoreFloat4( reinterpret_cast( &Color[i] ), pColor[i] ); + XMStoreFloat4(reinterpret_cast(&Color[i]), pColor[i]); } auto pBC3 = reinterpret_cast(pBC); @@ -961,7 +970,7 @@ void D3DXEncodeBC3(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) if (flags & BC_FLAGS_DITHER_A) memset(fError, 0x00, NUM_PIXELS_PER_BLOCK * sizeof(float)); - for(size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { float fAlph = Color[i].a; if (flags & BC_FLAGS_DITHER_A) @@ -969,33 +978,33 @@ void D3DXEncodeBC3(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) fAlpha[i] = static_cast(fAlph * 255.0f + 0.5f) * (1.0f / 255.0f); - if(fAlpha[i] < fMinAlpha) + if (fAlpha[i] < fMinAlpha) fMinAlpha = fAlpha[i]; - else if(fAlpha[i] > fMaxAlpha) + else if (fAlpha[i] > fMaxAlpha) fMaxAlpha = fAlpha[i]; - + if (flags & BC_FLAGS_DITHER_A) { float fDiff = fAlph - fAlpha[i]; - if(3 != (i & 3)) + if (3 != (i & 3)) { - assert( i < 15 ); - _Analysis_assume_( i < 15 ); + assert(i < 15); + _Analysis_assume_(i < 15); fError[i + 1] += fDiff * (7.0f / 16.0f); } - if(i < 12) + if (i < 12) { - if(i & 3) + if (i & 3) fError[i + 3] += fDiff * (3.0f / 16.0f); fError[i + 4] += fDiff * (5.0f / 16.0f); - if(3 != (i & 3)) + if (3 != (i & 3)) { - assert( i < 11 ); - _Analysis_assume_( i < 11 ); + assert(i < 11); + _Analysis_assume_(i < 11); fError[i + 5] += fDiff * (1.0f / 16.0f); } } @@ -1003,7 +1012,7 @@ void D3DXEncodeBC3(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) } #ifdef COLOR_WEIGHTS - if(0.0f == fMaxAlpha) + if (0.0f == fMaxAlpha) { EncodeSolidBC1(&pBC3->dxt1, Color); pBC3->alpha[0] = 0x00; @@ -1016,7 +1025,7 @@ void D3DXEncodeBC3(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) EncodeBC1(&pBC3->bc1, Color, false, 0.f, flags); // Alpha part - if(1.0f == fMinAlpha) + if (1.0f == fMinAlpha) { pBC3->alpha[0] = 0xff; pBC3->alpha[1] = 0xff; @@ -1033,11 +1042,11 @@ void D3DXEncodeBC3(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) uint8_t bAlphaA = (uint8_t) static_cast(fAlphaA * 255.0f + 0.5f); uint8_t bAlphaB = (uint8_t) static_cast(fAlphaB * 255.0f + 0.5f); - fAlphaA = (float) bAlphaA * (1.0f / 255.0f); - fAlphaB = (float) bAlphaB * (1.0f / 255.0f); + fAlphaA = (float)bAlphaA * (1.0f / 255.0f); + fAlphaB = (float)bAlphaB * (1.0f / 255.0f); // Setup block - if((8 == uSteps) && (bAlphaA == bAlphaB)) + if ((8 == uSteps) && (bAlphaA == bAlphaB)) { pBC3->alpha[0] = bAlphaA; pBC3->alpha[1] = bAlphaB; @@ -1051,7 +1060,7 @@ void D3DXEncodeBC3(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) const size_t *pSteps; float fStep[8]; - if(6 == uSteps) + if (6 == uSteps) { pBC3->alpha[0] = bAlphaA; pBC3->alpha[1] = bAlphaB; @@ -1059,7 +1068,7 @@ void D3DXEncodeBC3(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) fStep[0] = fAlphaA; fStep[1] = fAlphaB; - for(size_t i = 1; i < 5; ++i) + for (size_t i = 1; i < 5; ++i) fStep[i + 1] = (fStep[0] * (5 - i) + fStep[1] * i) * (1.0f / 5.0f); fStep[6] = 0.0f; @@ -1075,27 +1084,27 @@ void D3DXEncodeBC3(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) fStep[0] = fAlphaB; fStep[1] = fAlphaA; - for(size_t i = 1; i < 7; ++i) + for (size_t i = 1; i < 7; ++i) fStep[i + 1] = (fStep[0] * (7 - i) + fStep[1] * i) * (1.0f / 7.0f); pSteps = pSteps8; } // Encode alpha bitmap - float fSteps = (float) (uSteps - 1); + float fSteps = (float)(uSteps - 1); float fScale = (fStep[0] != fStep[1]) ? (fSteps / (fStep[1] - fStep[0])) : 0.0f; if (flags & BC_FLAGS_DITHER_A) memset(fError, 0x00, NUM_PIXELS_PER_BLOCK * sizeof(float)); - for(size_t iSet = 0; iSet < 2; iSet++) + for (size_t iSet = 0; iSet < 2; iSet++) { uint32_t dw = 0; size_t iMin = iSet * 8; size_t iLim = iMin + 8; - for(size_t i = iMin; i < iLim; ++i) + for (size_t i = iMin; i < iLim; ++i) { float fAlph = Color[i].a; if (flags & BC_FLAGS_DITHER_A) @@ -1103,12 +1112,12 @@ void D3DXEncodeBC3(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) float fDot = (fAlph - fStep[0]) * fScale; uint32_t iStep; - if(fDot <= 0.0f) + if (fDot <= 0.0f) iStep = ((6 == uSteps) && (fAlph <= fStep[0] * 0.5f)) ? 6 : 0; - else if(fDot >= fSteps) + else if (fDot >= fSteps) iStep = ((6 == uSteps) && (fAlph >= (fStep[1] + 1.0f) * 0.5f)) ? 7 : 1; else - iStep = static_cast( pSteps[static_cast(fDot + 0.5f)] ); + iStep = static_cast(pSteps[static_cast(fDot + 0.5f)]); dw = (iStep << 21) | (dw >> 3); @@ -1116,26 +1125,24 @@ void D3DXEncodeBC3(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) { float fDiff = (fAlph - fStep[iStep]); - if(3 != (i & 3)) + if (3 != (i & 3)) fError[i + 1] += fDiff * (7.0f / 16.0f); - if(i < 12) + if (i < 12) { - if(i & 3) + if (i & 3) fError[i + 3] += fDiff * (3.0f / 16.0f); fError[i + 4] += fDiff * (5.0f / 16.0f); - if(3 != (i & 3)) + if (3 != (i & 3)) fError[i + 5] += fDiff * (1.0f / 16.0f); } } } - pBC3->bitmap[0 + iSet * 3] = ((uint8_t *) &dw)[0]; - pBC3->bitmap[1 + iSet * 3] = ((uint8_t *) &dw)[1]; - pBC3->bitmap[2 + iSet * 3] = ((uint8_t *) &dw)[2]; + pBC3->bitmap[0 + iSet * 3] = ((uint8_t *)&dw)[0]; + pBC3->bitmap[1 + iSet * 3] = ((uint8_t *)&dw)[1]; + pBC3->bitmap[2 + iSet * 3] = ((uint8_t *)&dw)[2]; } } - -} // namespace diff --git a/DirectXTex/BC4BC5.cpp b/DirectXTex/BC4BC5.cpp index 1c0698b..9c6eee3 100644 --- a/DirectXTex/BC4BC5.cpp +++ b/DirectXTex/BC4BC5.cpp @@ -17,8 +17,7 @@ #include "BC.h" -namespace DirectX -{ +using namespace DirectX; //------------------------------------------------------------------------------------ // Constants @@ -26,338 +25,361 @@ namespace DirectX // Because these are used in SAL annotations, they need to remain macros rather than const values #define BLOCK_LEN 4 - // length of each block in texel +// length of each block in texel #define BLOCK_SIZE (BLOCK_LEN * BLOCK_LEN) - // total texels in a 4x4 block. +// total texels in a 4x4 block. -//------------------------------------------------------------------------------------ -// Structures -//------------------------------------------------------------------------------------- +namespace +{ + //------------------------------------------------------------------------------------ + // Structures + //------------------------------------------------------------------------------------- #pragma warning(push) #pragma warning(disable : 4201) -// BC4U/BC5U -struct BC4_UNORM -{ - float R(size_t uOffset) const + // BC4U/BC5U + struct BC4_UNORM { - size_t uIndex = GetIndex(uOffset); - return DecodeFromIndex(uIndex); - } - - float DecodeFromIndex(size_t uIndex) const - { - if (uIndex == 0) - return red_0 / 255.0f; - if (uIndex == 1) - return red_1 / 255.0f; - float fred_0 = red_0 / 255.0f; - float fred_1 = red_1 / 255.0f; - if (red_0 > red_1) + float R(size_t uOffset) const { - uIndex -= 1; - return (fred_0 * (7-uIndex) + fred_1 * uIndex) / 7.0f; + size_t uIndex = GetIndex(uOffset); + return DecodeFromIndex(uIndex); } - else + + float DecodeFromIndex(size_t uIndex) const { - if (uIndex == 6) - return 0.0f; - if (uIndex == 7) - return 1.0f; - uIndex -= 1; - return (fred_0 * (5-uIndex) + fred_1 * uIndex) / 5.0f; + if (uIndex == 0) + return red_0 / 255.0f; + if (uIndex == 1) + return red_1 / 255.0f; + float fred_0 = red_0 / 255.0f; + float fred_1 = red_1 / 255.0f; + if (red_0 > red_1) + { + uIndex -= 1; + return (fred_0 * (7 - uIndex) + fred_1 * uIndex) / 7.0f; + } + else + { + if (uIndex == 6) + return 0.0f; + if (uIndex == 7) + return 1.0f; + uIndex -= 1; + return (fred_0 * (5 - uIndex) + fred_1 * uIndex) / 5.0f; + } } - } - size_t GetIndex(size_t uOffset) const - { - return (size_t) ((data >> (3*uOffset + 16)) & 0x07); - } - - void SetIndex(size_t uOffset, size_t uIndex) - { - data &= ~((uint64_t) 0x07 << (3*uOffset + 16)); - data |= ((uint64_t) uIndex << (3*uOffset + 16)); - } - - union - { - struct + size_t GetIndex(size_t uOffset) const { - uint8_t red_0; - uint8_t red_1; - uint8_t indices[6]; + return (size_t)((data >> (3 * uOffset + 16)) & 0x07); + } + + void SetIndex(size_t uOffset, size_t uIndex) + { + data &= ~((uint64_t)0x07 << (3 * uOffset + 16)); + data |= ((uint64_t)uIndex << (3 * uOffset + 16)); + } + + union + { + struct + { + uint8_t red_0; + uint8_t red_1; + uint8_t indices[6]; + }; + uint64_t data; }; - uint64_t data; }; -}; -// BC4S/BC5S -struct BC4_SNORM -{ - float R(size_t uOffset) const + // BC4S/BC5S + struct BC4_SNORM { - size_t uIndex = GetIndex(uOffset); - return DecodeFromIndex(uIndex); - } - - float DecodeFromIndex(size_t uIndex) const - { - int8_t sred_0 = (red_0 == -128)? -127 : red_0; - int8_t sred_1 = (red_1 == -128)? -127 : red_1; - - if (uIndex == 0) - return sred_0 / 127.0f; - if (uIndex == 1) - return sred_1 / 127.0f; - float fred_0 = sred_0 / 127.0f; - float fred_1 = sred_1 / 127.0f; - if (red_0 > red_1) + float R(size_t uOffset) const { - uIndex -= 1; - return (fred_0 * (7-uIndex) + fred_1 * uIndex) / 7.0f; + size_t uIndex = GetIndex(uOffset); + return DecodeFromIndex(uIndex); } - else + + float DecodeFromIndex(size_t uIndex) const { - if (uIndex == 6) - return -1.0f; - if (uIndex == 7) - return 1.0f; - uIndex -= 1; - return (fred_0 * (5-uIndex) + fred_1 * uIndex) / 5.0f; + int8_t sred_0 = (red_0 == -128) ? -127 : red_0; + int8_t sred_1 = (red_1 == -128) ? -127 : red_1; + + if (uIndex == 0) + return sred_0 / 127.0f; + if (uIndex == 1) + return sred_1 / 127.0f; + float fred_0 = sred_0 / 127.0f; + float fred_1 = sred_1 / 127.0f; + if (red_0 > red_1) + { + uIndex -= 1; + return (fred_0 * (7 - uIndex) + fred_1 * uIndex) / 7.0f; + } + else + { + if (uIndex == 6) + return -1.0f; + if (uIndex == 7) + return 1.0f; + uIndex -= 1; + return (fred_0 * (5 - uIndex) + fred_1 * uIndex) / 5.0f; + } } - } - size_t GetIndex(size_t uOffset) const - { - return (size_t) ((data >> (3*uOffset + 16)) & 0x07); - } - - void SetIndex(size_t uOffset, size_t uIndex) - { - data &= ~((uint64_t) 0x07 << (3*uOffset + 16)); - data |= ((uint64_t) uIndex << (3*uOffset + 16)); - } - - union - { - struct + size_t GetIndex(size_t uOffset) const { - int8_t red_0; - int8_t red_1; - uint8_t indices[6]; + return (size_t)((data >> (3 * uOffset + 16)) & 0x07); + } + + void SetIndex(size_t uOffset, size_t uIndex) + { + data &= ~((uint64_t)0x07 << (3 * uOffset + 16)); + data |= ((uint64_t)uIndex << (3 * uOffset + 16)); + } + + union + { + struct + { + int8_t red_0; + int8_t red_1; + uint8_t indices[6]; + }; + uint64_t data; }; - uint64_t data; }; -}; #pragma warning(pop) -//------------------------------------------------------------------------------------- -// Convert a floating point value to an 8-bit SNORM -//------------------------------------------------------------------------------------- -static void inline FloatToSNorm( _In_ float fVal, _Out_ int8_t *piSNorm ) -{ - const uint32_t dwMostNeg = ( 1 << ( 8 * sizeof( int8_t ) - 1 ) ); + //------------------------------------------------------------------------------------- + // Convert a floating point value to an 8-bit SNORM + //------------------------------------------------------------------------------------- + void inline FloatToSNorm(_In_ float fVal, _Out_ int8_t *piSNorm) + { + const uint32_t dwMostNeg = (1 << (8 * sizeof(int8_t) - 1)); - if( _isnan( fVal ) ) - fVal = 0; - else - if( fVal > 1 ) - fVal = 1; // Clamp to 1 + if (_isnan(fVal)) + fVal = 0; else - if( fVal < -1 ) - fVal = -1; // Clamp to -1 + if (fVal > 1) + fVal = 1; // Clamp to 1 + else + if (fVal < -1) + fVal = -1; // Clamp to -1 - fVal = fVal * (int8_t) ( dwMostNeg - 1 ); + fVal = fVal * (int8_t)(dwMostNeg - 1); - if( fVal >= 0 ) - fVal += .5f; - else - fVal -= .5f; + if (fVal >= 0) + fVal += .5f; + else + fVal -= .5f; - *piSNorm = (int8_t) (fVal); -} - - -//------------------------------------------------------------------------------ -static void FindEndPointsBC4U( _In_reads_(BLOCK_SIZE) const float theTexelsU[], _Out_ uint8_t &endpointU_0, _Out_ uint8_t &endpointU_1) -{ - // The boundary of codec for signed/unsigned format - float MIN_NORM; - float MAX_NORM = 1.0f; - int8_t iStart, iEnd; - size_t i; - - MIN_NORM = 0.0f; - - // Find max/min of input texels - float fBlockMax = theTexelsU[0]; - float fBlockMin = theTexelsU[0]; - for (i = 0; i < BLOCK_SIZE; ++i) - { - if (theTexelsU[i]fBlockMax) - { - fBlockMax = theTexelsU[i]; - } + *piSNorm = (int8_t)(fVal); } - // If there are boundary values in input texels, Should use 4 block-codec to guarantee - // the exact code of the boundary values. - bool bUsing4BlockCodec = ( MIN_NORM == fBlockMin || MAX_NORM == fBlockMax ); - // Using Optimize - float fStart, fEnd; - - if (!bUsing4BlockCodec) - { - OptimizeAlpha(&fStart, &fEnd, theTexelsU, 8); - - iStart = (uint8_t) (fStart * 255.0f); - iEnd = (uint8_t) (fEnd * 255.0f); - - endpointU_0 = iEnd; - endpointU_1 = iStart; - } - else + //------------------------------------------------------------------------------ + void FindEndPointsBC4U( + _In_reads_(BLOCK_SIZE) const float theTexelsU[], + _Out_ uint8_t &endpointU_0, + _Out_ uint8_t &endpointU_1) { - OptimizeAlpha(&fStart, &fEnd, theTexelsU, 6); + // The boundary of codec for signed/unsigned format + float MIN_NORM; + float MAX_NORM = 1.0f; + int8_t iStart, iEnd; + size_t i; - iStart = (uint8_t) (fStart * 255.0f); - iEnd = (uint8_t) (fEnd * 255.0f); + MIN_NORM = 0.0f; - endpointU_1 = iEnd; - endpointU_0 = iStart; - } -} - -static void FindEndPointsBC4S(_In_reads_(BLOCK_SIZE) const float theTexelsU[], _Out_ int8_t &endpointU_0, _Out_ int8_t &endpointU_1) -{ - // The boundary of codec for signed/unsigned format - float MIN_NORM; - float MAX_NORM = 1.0f; - int8_t iStart, iEnd; - size_t i; - - MIN_NORM = -1.0f; - - // Find max/min of input texels - float fBlockMax = theTexelsU[0]; - float fBlockMin = theTexelsU[0]; - for (i = 0; i < BLOCK_SIZE; ++i) - { - if (theTexelsU[i]fBlockMax) - { - fBlockMax = theTexelsU[i]; - } - } - - // If there are boundary values in input texels, Should use 4 block-codec to guarantee - // the exact code of the boundary values. - bool bUsing4BlockCodec = ( MIN_NORM == fBlockMin || MAX_NORM == fBlockMax ); - - // Using Optimize - float fStart, fEnd; - - if (!bUsing4BlockCodec) - { - OptimizeAlpha(&fStart, &fEnd, theTexelsU, 8); - - FloatToSNorm(fStart, &iStart); - FloatToSNorm(fEnd, &iEnd); - - endpointU_0 = iEnd; - endpointU_1 = iStart; - } - else - { - OptimizeAlpha(&fStart, &fEnd, theTexelsU, 6); - - FloatToSNorm(fStart, &iStart); - FloatToSNorm(fEnd, &iEnd); - - endpointU_1 = iEnd; - endpointU_0 = iStart; - } -} - - -//------------------------------------------------------------------------------ -static inline void FindEndPointsBC5U( _In_reads_(BLOCK_SIZE) const float theTexelsU[], _In_reads_(BLOCK_SIZE) const float theTexelsV[], - _Out_ uint8_t &endpointU_0, _Out_ uint8_t &endpointU_1, _Out_ uint8_t &endpointV_0, _Out_ uint8_t &endpointV_1) -{ - //Encoding the U and V channel by BC4 codec separately. - FindEndPointsBC4U( theTexelsU, endpointU_0, endpointU_1); - FindEndPointsBC4U( theTexelsV, endpointV_0, endpointV_1); -} - -static inline void FindEndPointsBC5S( _In_reads_(BLOCK_SIZE) const float theTexelsU[], _In_reads_(BLOCK_SIZE) const float theTexelsV[], - _Out_ int8_t &endpointU_0, _Out_ int8_t &endpointU_1, _Out_ int8_t &endpointV_0, _Out_ int8_t &endpointV_1) -{ - //Encoding the U and V channel by BC4 codec separately. - FindEndPointsBC4S( theTexelsU, endpointU_0, endpointU_1); - FindEndPointsBC4S( theTexelsV, endpointV_0, endpointV_1); -} - - -//------------------------------------------------------------------------------ -static void FindClosestUNORM(_Inout_ BC4_UNORM* pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) const float theTexelsU[]) -{ - float rGradient[8]; - int i; - for (i = 0; i < 8; ++i) - { - rGradient[i] = pBC->DecodeFromIndex(i); - } - for (i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) - { - size_t uBestIndex = 0; - float fBestDelta = 100000; - for (size_t uIndex = 0; uIndex < 8; uIndex++) - { - float fCurrentDelta = fabsf(rGradient[uIndex]-theTexelsU[i]); - if (fCurrentDelta < fBestDelta) + if (theTexelsU[i] < fBlockMin) { - uBestIndex = uIndex; - fBestDelta = fCurrentDelta; + fBlockMin = theTexelsU[i]; + } + else if (theTexelsU[i] > fBlockMax) + { + fBlockMax = theTexelsU[i]; } } - pBC->SetIndex(i, uBestIndex); - } -} -static void FindClosestSNORM(_Inout_ BC4_SNORM* pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) const float theTexelsU[]) -{ - float rGradient[8]; - int i; - for (i = 0; i < 8; ++i) - { - rGradient[i] = pBC->DecodeFromIndex(i); - } - for (i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) - { - size_t uBestIndex = 0; - float fBestDelta = 100000; - for (size_t uIndex = 0; uIndex < 8; uIndex++) + // If there are boundary values in input texels, Should use 4 block-codec to guarantee + // the exact code of the boundary values. + bool bUsing4BlockCodec = (MIN_NORM == fBlockMin || MAX_NORM == fBlockMax); + + // Using Optimize + float fStart, fEnd; + + if (!bUsing4BlockCodec) { - float fCurrentDelta = fabsf(rGradient[uIndex]-theTexelsU[i]); - if (fCurrentDelta < fBestDelta) + OptimizeAlpha(&fStart, &fEnd, theTexelsU, 8); + + iStart = (uint8_t)(fStart * 255.0f); + iEnd = (uint8_t)(fEnd * 255.0f); + + endpointU_0 = iEnd; + endpointU_1 = iStart; + } + else + { + OptimizeAlpha(&fStart, &fEnd, theTexelsU, 6); + + iStart = (uint8_t)(fStart * 255.0f); + iEnd = (uint8_t)(fEnd * 255.0f); + + endpointU_1 = iEnd; + endpointU_0 = iStart; + } + } + + void FindEndPointsBC4S( + _In_reads_(BLOCK_SIZE) const float theTexelsU[], + _Out_ int8_t &endpointU_0, + _Out_ int8_t &endpointU_1) + { + // The boundary of codec for signed/unsigned format + float MIN_NORM; + float MAX_NORM = 1.0f; + int8_t iStart, iEnd; + size_t i; + + MIN_NORM = -1.0f; + + // Find max/min of input texels + float fBlockMax = theTexelsU[0]; + float fBlockMin = theTexelsU[0]; + for (i = 0; i < BLOCK_SIZE; ++i) + { + if (theTexelsU[i] < fBlockMin) { - uBestIndex = uIndex; - fBestDelta = fCurrentDelta; + fBlockMin = theTexelsU[i]; + } + else if (theTexelsU[i] > fBlockMax) + { + fBlockMax = theTexelsU[i]; } } - pBC->SetIndex(i, uBestIndex); + + // If there are boundary values in input texels, Should use 4 block-codec to guarantee + // the exact code of the boundary values. + bool bUsing4BlockCodec = (MIN_NORM == fBlockMin || MAX_NORM == fBlockMax); + + // Using Optimize + float fStart, fEnd; + + if (!bUsing4BlockCodec) + { + OptimizeAlpha(&fStart, &fEnd, theTexelsU, 8); + + FloatToSNorm(fStart, &iStart); + FloatToSNorm(fEnd, &iEnd); + + endpointU_0 = iEnd; + endpointU_1 = iStart; + } + else + { + OptimizeAlpha(&fStart, &fEnd, theTexelsU, 6); + + FloatToSNorm(fStart, &iStart); + FloatToSNorm(fEnd, &iEnd); + + endpointU_1 = iEnd; + endpointU_0 = iStart; + } + } + + + //------------------------------------------------------------------------------ + inline void FindEndPointsBC5U( + _In_reads_(BLOCK_SIZE) const float theTexelsU[], + _In_reads_(BLOCK_SIZE) const float theTexelsV[], + _Out_ uint8_t &endpointU_0, + _Out_ uint8_t &endpointU_1, + _Out_ uint8_t &endpointV_0, + _Out_ uint8_t &endpointV_1) + { + //Encoding the U and V channel by BC4 codec separately. + FindEndPointsBC4U(theTexelsU, endpointU_0, endpointU_1); + FindEndPointsBC4U(theTexelsV, endpointV_0, endpointV_1); + } + + inline void FindEndPointsBC5S( + _In_reads_(BLOCK_SIZE) const float theTexelsU[], + _In_reads_(BLOCK_SIZE) const float theTexelsV[], + _Out_ int8_t &endpointU_0, + _Out_ int8_t &endpointU_1, + _Out_ int8_t &endpointV_0, + _Out_ int8_t &endpointV_1) + { + //Encoding the U and V channel by BC4 codec separately. + FindEndPointsBC4S(theTexelsU, endpointU_0, endpointU_1); + FindEndPointsBC4S(theTexelsV, endpointV_0, endpointV_1); + } + + + //------------------------------------------------------------------------------ + void FindClosestUNORM( + _Inout_ BC4_UNORM* pBC, + _In_reads_(NUM_PIXELS_PER_BLOCK) const float theTexelsU[]) + { + float rGradient[8]; + int i; + for (i = 0; i < 8; ++i) + { + rGradient[i] = pBC->DecodeFromIndex(i); + } + for (i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + { + size_t uBestIndex = 0; + float fBestDelta = 100000; + for (size_t uIndex = 0; uIndex < 8; uIndex++) + { + float fCurrentDelta = fabsf(rGradient[uIndex] - theTexelsU[i]); + if (fCurrentDelta < fBestDelta) + { + uBestIndex = uIndex; + fBestDelta = fCurrentDelta; + } + } + pBC->SetIndex(i, uBestIndex); + } + } + + void FindClosestSNORM( + _Inout_ BC4_SNORM* pBC, + _In_reads_(NUM_PIXELS_PER_BLOCK) const float theTexelsU[]) + { + float rGradient[8]; + int i; + for (i = 0; i < 8; ++i) + { + rGradient[i] = pBC->DecodeFromIndex(i); + } + for (i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + { + size_t uBestIndex = 0; + float fBestDelta = 100000; + for (size_t uIndex = 0; uIndex < 8; uIndex++) + { + float fCurrentDelta = fabsf(rGradient[uIndex] - theTexelsU[i]); + if (fCurrentDelta < fBestDelta) + { + uBestIndex = uIndex; + fBestDelta = fCurrentDelta; + } + } + pBC->SetIndex(i, uBestIndex); + } } } @@ -370,42 +392,42 @@ static void FindClosestSNORM(_Inout_ BC4_SNORM* pBC, _In_reads_(NUM_PIXELS_PER_B // BC4 Compression //------------------------------------------------------------------------------------- _Use_decl_annotations_ -void D3DXDecodeBC4U( XMVECTOR *pColor, const uint8_t *pBC ) +void DirectX::D3DXDecodeBC4U(XMVECTOR *pColor, const uint8_t *pBC) { - assert( pColor && pBC ); - static_assert( sizeof(BC4_UNORM) == 8, "BC4_UNORM should be 8 bytes" ); + assert(pColor && pBC); + static_assert(sizeof(BC4_UNORM) == 8, "BC4_UNORM should be 8 bytes"); auto pBC4 = reinterpret_cast(pBC); for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { - #pragma prefast(suppress:22103, "writing blocks in two halves confuses tool") - pColor[i] = XMVectorSet( pBC4->R(i), 0, 0, 1.0f); - } +#pragma prefast(suppress:22103, "writing blocks in two halves confuses tool") + pColor[i] = XMVectorSet(pBC4->R(i), 0, 0, 1.0f); + } } _Use_decl_annotations_ -void D3DXDecodeBC4S(XMVECTOR *pColor, const uint8_t *pBC) +void DirectX::D3DXDecodeBC4S(XMVECTOR *pColor, const uint8_t *pBC) { - assert( pColor && pBC ); - static_assert( sizeof(BC4_SNORM) == 8, "BC4_SNORM should be 8 bytes" ); + assert(pColor && pBC); + static_assert(sizeof(BC4_SNORM) == 8, "BC4_SNORM should be 8 bytes"); auto pBC4 = reinterpret_cast(pBC); for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { - #pragma prefast(suppress:22103, "writing blocks in two halves confuses tool") - pColor[i] = XMVectorSet( pBC4->R(i), 0, 0, 1.0f); - } +#pragma prefast(suppress:22103, "writing blocks in two halves confuses tool") + pColor[i] = XMVectorSet(pBC4->R(i), 0, 0, 1.0f); + } } _Use_decl_annotations_ -void D3DXEncodeBC4U( uint8_t *pBC, const XMVECTOR *pColor, DWORD flags ) +void DirectX::D3DXEncodeBC4U(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) { - UNREFERENCED_PARAMETER( flags ); + UNREFERENCED_PARAMETER(flags); - assert( pBC && pColor ); - static_assert( sizeof(BC4_UNORM) == 8, "BC4_UNORM should be 8 bytes" ); + assert(pBC && pColor); + static_assert(sizeof(BC4_UNORM) == 8, "BC4_UNORM should be 8 bytes"); memset(pBC, 0, sizeof(BC4_UNORM)); auto pBC4 = reinterpret_cast(pBC); @@ -413,7 +435,7 @@ void D3DXEncodeBC4U( uint8_t *pBC, const XMVECTOR *pColor, DWORD flags ) for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { - theTexelsU[i] = XMVectorGetX( pColor[i] ); + theTexelsU[i] = XMVectorGetX(pColor[i]); } FindEndPointsBC4U(theTexelsU, pBC4->red_0, pBC4->red_1); @@ -421,12 +443,12 @@ void D3DXEncodeBC4U( uint8_t *pBC, const XMVECTOR *pColor, DWORD flags ) } _Use_decl_annotations_ -void D3DXEncodeBC4S( uint8_t *pBC, const XMVECTOR *pColor, DWORD flags ) +void DirectX::D3DXEncodeBC4S(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) { - UNREFERENCED_PARAMETER( flags ); + UNREFERENCED_PARAMETER(flags); - assert( pBC && pColor ); - static_assert( sizeof(BC4_SNORM) == 8, "BC4_SNORM should be 8 bytes" ); + assert(pBC && pColor); + static_assert(sizeof(BC4_SNORM) == 8, "BC4_SNORM should be 8 bytes"); memset(pBC, 0, sizeof(BC4_UNORM)); auto pBC4 = reinterpret_cast(pBC); @@ -434,7 +456,7 @@ void D3DXEncodeBC4S( uint8_t *pBC, const XMVECTOR *pColor, DWORD flags ) for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { - theTexelsU[i] = XMVectorGetX( pColor[i] ); + theTexelsU[i] = XMVectorGetX(pColor[i]); } FindEndPointsBC4S(theTexelsU, pBC4->red_0, pBC4->red_1); @@ -446,55 +468,55 @@ void D3DXEncodeBC4S( uint8_t *pBC, const XMVECTOR *pColor, DWORD flags ) // BC5 Compression //------------------------------------------------------------------------------------- _Use_decl_annotations_ -void D3DXDecodeBC5U(XMVECTOR *pColor, const uint8_t *pBC) +void DirectX::D3DXDecodeBC5U(XMVECTOR *pColor, const uint8_t *pBC) { - assert( pColor && pBC ); - static_assert( sizeof(BC4_UNORM) == 8, "BC4_UNORM should be 8 bytes" ); + assert(pColor && pBC); + static_assert(sizeof(BC4_UNORM) == 8, "BC4_UNORM should be 8 bytes"); auto pBCR = reinterpret_cast(pBC); - auto pBCG = reinterpret_cast(pBC+sizeof(BC4_UNORM)); + auto pBCG = reinterpret_cast(pBC + sizeof(BC4_UNORM)); for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { - #pragma prefast(suppress:22103, "writing blocks in two halves confuses tool") +#pragma prefast(suppress:22103, "writing blocks in two halves confuses tool") pColor[i] = XMVectorSet(pBCR->R(i), pBCG->R(i), 0, 1.0f); - } + } } _Use_decl_annotations_ -void D3DXDecodeBC5S(XMVECTOR *pColor, const uint8_t *pBC) +void DirectX::D3DXDecodeBC5S(XMVECTOR *pColor, const uint8_t *pBC) { - assert( pColor && pBC ); - static_assert( sizeof(BC4_SNORM) == 8, "BC4_SNORM should be 8 bytes" ); + assert(pColor && pBC); + static_assert(sizeof(BC4_SNORM) == 8, "BC4_SNORM should be 8 bytes"); auto pBCR = reinterpret_cast(pBC); - auto pBCG = reinterpret_cast(pBC+sizeof(BC4_SNORM)); + auto pBCG = reinterpret_cast(pBC + sizeof(BC4_SNORM)); for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { - #pragma prefast(suppress:22103, "writing blocks in two halves confuses tool") +#pragma prefast(suppress:22103, "writing blocks in two halves confuses tool") pColor[i] = XMVectorSet(pBCR->R(i), pBCG->R(i), 0, 1.0f); - } + } } _Use_decl_annotations_ -void D3DXEncodeBC5U( uint8_t *pBC, const XMVECTOR *pColor, DWORD flags ) +void DirectX::D3DXEncodeBC5U(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) { - UNREFERENCED_PARAMETER( flags ); + UNREFERENCED_PARAMETER(flags); - assert( pBC && pColor ); - static_assert( sizeof(BC4_UNORM) == 8, "BC4_UNORM should be 8 bytes" ); + assert(pBC && pColor); + static_assert(sizeof(BC4_UNORM) == 8, "BC4_UNORM should be 8 bytes"); - memset(pBC, 0, sizeof(BC4_UNORM)*2); + memset(pBC, 0, sizeof(BC4_UNORM) * 2); auto pBCR = reinterpret_cast(pBC); - auto pBCG = reinterpret_cast(pBC+sizeof(BC4_UNORM)); + auto pBCG = reinterpret_cast(pBC + sizeof(BC4_UNORM)); float theTexelsU[NUM_PIXELS_PER_BLOCK]; float theTexelsV[NUM_PIXELS_PER_BLOCK]; for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) - { + { XMFLOAT4A clr; - XMStoreFloat4A( &clr, pColor[i] ); + XMStoreFloat4A(&clr, pColor[i]); theTexelsU[i] = clr.x; theTexelsV[i] = clr.y; } @@ -512,23 +534,23 @@ void D3DXEncodeBC5U( uint8_t *pBC, const XMVECTOR *pColor, DWORD flags ) } _Use_decl_annotations_ -void D3DXEncodeBC5S( uint8_t *pBC, const XMVECTOR *pColor, DWORD flags ) +void DirectX::D3DXEncodeBC5S(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) { - UNREFERENCED_PARAMETER( flags ); + UNREFERENCED_PARAMETER(flags); - assert( pBC && pColor ); - static_assert( sizeof(BC4_SNORM) == 8, "BC4_SNORM should be 8 bytes" ); + assert(pBC && pColor); + static_assert(sizeof(BC4_SNORM) == 8, "BC4_SNORM should be 8 bytes"); - memset(pBC, 0, sizeof(BC4_UNORM)*2); + memset(pBC, 0, sizeof(BC4_UNORM) * 2); auto pBCR = reinterpret_cast(pBC); - auto pBCG = reinterpret_cast(pBC+sizeof(BC4_SNORM)); + auto pBCG = reinterpret_cast(pBC + sizeof(BC4_SNORM)); float theTexelsU[NUM_PIXELS_PER_BLOCK]; float theTexelsV[NUM_PIXELS_PER_BLOCK]; for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { XMFLOAT4A clr; - XMStoreFloat4A( &clr, pColor[i] ); + XMStoreFloat4A(&clr, pColor[i]); theTexelsU[i] = clr.x; theTexelsV[i] = clr.y; } @@ -543,6 +565,4 @@ void D3DXEncodeBC5S( uint8_t *pBC, const XMVECTOR *pColor, DWORD flags ) FindClosestSNORM(pBCR, theTexelsU); FindClosestSNORM(pBCG, theTexelsV); -} - -} // namespace +} \ No newline at end of file diff --git a/DirectXTex/BC6HBC7.cpp b/DirectXTex/BC6HBC7.cpp index 58d64be..9ac1d76 100644 --- a/DirectXTex/BC6HBC7.cpp +++ b/DirectXTex/BC6HBC7.cpp @@ -17,294 +17,298 @@ #include "BC.h" +using namespace DirectX; using namespace DirectX::PackedVector; +namespace +{ + //------------------------------------------------------------------------------------- + // Constants + //------------------------------------------------------------------------------------- + + const float fEpsilon = (0.25f / 64.0f) * (0.25f / 64.0f); + const float pC3[] = { 2.0f / 2.0f, 1.0f / 2.0f, 0.0f / 2.0f }; + const float pD3[] = { 0.0f / 2.0f, 1.0f / 2.0f, 2.0f / 2.0f }; + const float pC4[] = { 3.0f / 3.0f, 2.0f / 3.0f, 1.0f / 3.0f, 0.0f / 3.0f }; + const float pD4[] = { 0.0f / 3.0f, 1.0f / 3.0f, 2.0f / 3.0f, 3.0f / 3.0f }; + + // Partition, Shape, Pixel (index into 4x4 block) + const uint8_t g_aPartitionTable[3][64][16] = + { + { // 1 Region case has no subsets (all 0) + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + + { // BC6H/BC7 Partition Set for 2 Subsets + { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 }, // Shape 0 + { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 }, // Shape 1 + { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 }, // Shape 2 + { 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1 }, // Shape 3 + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 }, // Shape 4 + { 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, // Shape 5 + { 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, // Shape 6 + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1 }, // Shape 7 + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1 }, // Shape 8 + { 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 9 + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, // Shape 10 + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1 }, // Shape 11 + { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 12 + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 13 + { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 14 + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 }, // Shape 15 + { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1 }, // Shape 16 + { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, // Shape 17 + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0 }, // Shape 18 + { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 }, // Shape 19 + { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, // Shape 20 + { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0 }, // Shape 21 + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 }, // Shape 22 + { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1 }, // Shape 23 + { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 }, // Shape 24 + { 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 }, // Shape 25 + { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 }, // Shape 26 + { 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0 }, // Shape 27 + { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0 }, // Shape 28 + { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, // Shape 29 + { 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0 }, // Shape 30 + { 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0 }, // Shape 31 + + // BC7 Partition Set for 2 Subsets (second-half) + { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 }, // Shape 32 + { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 }, // Shape 33 + { 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0 }, // Shape 34 + { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0 }, // Shape 35 + { 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0 }, // Shape 36 + { 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0 }, // Shape 37 + { 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1 }, // Shape 38 + { 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1 }, // Shape 39 + { 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0 }, // Shape 40 + { 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0 }, // Shape 41 + { 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 }, // Shape 42 + { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0 }, // Shape 43 + { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }, // Shape 44 + { 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1 }, // Shape 45 + { 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1 }, // Shape 46 + { 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 }, // Shape 47 + { 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, // Shape 48 + { 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, // Shape 49 + { 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0 }, // Shape 50 + { 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0 }, // Shape 51 + { 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 }, // Shape 52 + { 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1 }, // Shape 53 + { 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0 }, // Shape 54 + { 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0 }, // Shape 55 + { 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1 }, // Shape 56 + { 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1 }, // Shape 57 + { 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1 }, // Shape 58 + { 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1 }, // Shape 59 + { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 }, // Shape 60 + { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, // Shape 61 + { 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0 }, // Shape 62 + { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1 } // Shape 63 + }, + + { // BC7 Partition Set for 3 Subsets + { 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 1, 2, 2, 2, 2 }, // Shape 0 + { 0, 0, 0, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1 }, // Shape 1 + { 0, 0, 0, 0, 2, 0, 0, 1, 2, 2, 1, 1, 2, 2, 1, 1 }, // Shape 2 + { 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 1, 0, 1, 1, 1 }, // Shape 3 + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2 }, // Shape 4 + { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 2, 2 }, // Shape 5 + { 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 6 + { 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1 }, // Shape 7 + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2 }, // Shape 8 + { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2 }, // Shape 9 + { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 10 + { 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2 }, // Shape 11 + { 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2 }, // Shape 12 + { 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2 }, // Shape 13 + { 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2 }, // Shape 14 + { 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0, 2, 2, 2, 0 }, // Shape 15 + { 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2 }, // Shape 16 + { 0, 1, 1, 1, 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0 }, // Shape 17 + { 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2 }, // Shape 18 + { 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1 }, // Shape 19 + { 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2 }, // Shape 20 + { 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 1, 2, 2, 2, 1 }, // Shape 21 + { 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2 }, // Shape 22 + { 0, 0, 0, 0, 1, 1, 0, 0, 2, 2, 1, 0, 2, 2, 1, 0 }, // Shape 23 + { 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1, 0, 0, 0, 0 }, // Shape 24 + { 0, 0, 1, 2, 0, 0, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2 }, // Shape 25 + { 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1, 0, 1, 1, 0 }, // Shape 26 + { 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1 }, // Shape 27 + { 0, 0, 2, 2, 1, 1, 0, 2, 1, 1, 0, 2, 0, 0, 2, 2 }, // Shape 28 + { 0, 1, 1, 0, 0, 1, 1, 0, 2, 0, 0, 2, 2, 2, 2, 2 }, // Shape 29 + { 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1 }, // Shape 30 + { 0, 0, 0, 0, 2, 0, 0, 0, 2, 2, 1, 1, 2, 2, 2, 1 }, // Shape 31 + { 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 2, 2, 2 }, // Shape 32 + { 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 2, 0, 0, 1, 1 }, // Shape 33 + { 0, 0, 1, 1, 0, 0, 1, 2, 0, 0, 2, 2, 0, 2, 2, 2 }, // Shape 34 + { 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0 }, // Shape 35 + { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0 }, // Shape 36 + { 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0 }, // Shape 37 + { 0, 1, 2, 0, 2, 0, 1, 2, 1, 2, 0, 1, 0, 1, 2, 0 }, // Shape 38 + { 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 0, 0, 1, 1 }, // Shape 39 + { 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1 }, // Shape 40 + { 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 41 + { 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1 }, // Shape 42 + { 0, 0, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2, 1, 1, 2, 2 }, // Shape 43 + { 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 1, 1 }, // Shape 44 + { 0, 2, 2, 0, 1, 2, 2, 1, 0, 2, 2, 0, 1, 2, 2, 1 }, // Shape 45 + { 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 1 }, // Shape 46 + { 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1 }, // Shape 47 + { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2 }, // Shape 48 + { 0, 2, 2, 2, 0, 1, 1, 1, 0, 2, 2, 2, 0, 1, 1, 1 }, // Shape 49 + { 0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 0, 2, 1, 1, 1, 2 }, // Shape 50 + { 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2 }, // Shape 51 + { 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2 }, // Shape 52 + { 0, 0, 0, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2 }, // Shape 53 + { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2 }, // Shape 54 + { 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2 }, // Shape 55 + { 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 56 + { 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2 }, // Shape 57 + { 0, 0, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2 }, // Shape 58 + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2 }, // Shape 59 + { 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1 }, // Shape 60 + { 0, 2, 2, 2, 1, 2, 2, 2, 0, 2, 2, 2, 1, 2, 2, 2 }, // Shape 61 + { 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 62 + { 0, 1, 1, 1, 2, 0, 1, 1, 2, 2, 0, 1, 2, 2, 2, 0 } // Shape 63 + } + }; + + // Partition, Shape, Fixup + const uint8_t g_aFixUp[3][64][3] = + { + { // No fix-ups for 1st subset for BC6H or BC7 + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0} + }, + + { // BC6H/BC7 Partition Set Fixups for 2 Subsets + { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, + { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, + { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, + { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, + { 0,15, 0}, { 0, 2, 0}, { 0, 8, 0}, { 0, 2, 0}, + { 0, 2, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0,15, 0}, + { 0, 2, 0}, { 0, 8, 0}, { 0, 2, 0}, { 0, 2, 0}, + { 0, 8, 0}, { 0, 8, 0}, { 0, 2, 0}, { 0, 2, 0}, + + // BC7 Partition Set Fixups for 2 Subsets (second-half) + { 0,15, 0}, { 0,15, 0}, { 0, 6, 0}, { 0, 8, 0}, + { 0, 2, 0}, { 0, 8, 0}, { 0,15, 0}, { 0,15, 0}, + { 0, 2, 0}, { 0, 8, 0}, { 0, 2, 0}, { 0, 2, 0}, + { 0, 2, 0}, { 0,15, 0}, { 0,15, 0}, { 0, 6, 0}, + { 0, 6, 0}, { 0, 2, 0}, { 0, 6, 0}, { 0, 8, 0}, + { 0,15, 0}, { 0,15, 0}, { 0, 2, 0}, { 0, 2, 0}, + { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, + { 0,15, 0}, { 0, 2, 0}, { 0, 2, 0}, { 0,15, 0} + }, + + { // BC7 Partition Set Fixups for 3 Subsets + { 0, 3,15}, { 0, 3, 8}, { 0,15, 8}, { 0,15, 3}, + { 0, 8,15}, { 0, 3,15}, { 0,15, 3}, { 0,15, 8}, + { 0, 8,15}, { 0, 8,15}, { 0, 6,15}, { 0, 6,15}, + { 0, 6,15}, { 0, 5,15}, { 0, 3,15}, { 0, 3, 8}, + { 0, 3,15}, { 0, 3, 8}, { 0, 8,15}, { 0,15, 3}, + { 0, 3,15}, { 0, 3, 8}, { 0, 6,15}, { 0,10, 8}, + { 0, 5, 3}, { 0, 8,15}, { 0, 8, 6}, { 0, 6,10}, + { 0, 8,15}, { 0, 5,15}, { 0,15,10}, { 0,15, 8}, + { 0, 8,15}, { 0,15, 3}, { 0, 3,15}, { 0, 5,10}, + { 0, 6,10}, { 0,10, 8}, { 0, 8, 9}, { 0,15,10}, + { 0,15, 6}, { 0, 3,15}, { 0,15, 8}, { 0, 5,15}, + { 0,15, 3}, { 0,15, 6}, { 0,15, 6}, { 0,15, 8}, + { 0, 3,15}, { 0,15, 3}, { 0, 5,15}, { 0, 5,15}, + { 0, 5,15}, { 0, 8,15}, { 0, 5,15}, { 0,10,15}, + { 0, 5,15}, { 0,10,15}, { 0, 8,15}, { 0,13,15}, + { 0,15, 3}, { 0,12,15}, { 0, 3,15}, { 0, 3, 8} + } + }; +} + namespace DirectX { - -//------------------------------------------------------------------------------------- -// Constants -//------------------------------------------------------------------------------------- - -static const float fEpsilon = (0.25f / 64.0f) * (0.25f / 64.0f); -static const float pC3[] = { 2.0f/2.0f, 1.0f/2.0f, 0.0f/2.0f }; -static const float pD3[] = { 0.0f/2.0f, 1.0f/2.0f, 2.0f/2.0f }; -static const float pC4[] = { 3.0f/3.0f, 2.0f/3.0f, 1.0f/3.0f, 0.0f/3.0f }; -static const float pD4[] = { 0.0f/3.0f, 1.0f/3.0f, 2.0f/3.0f, 3.0f/3.0f }; - -const int g_aWeights2[] = {0, 21, 43, 64}; -const int g_aWeights3[] = {0, 9, 18, 27, 37, 46, 55, 64}; -const int g_aWeights4[] = {0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64}; - -// Partition, Shape, Pixel (index into 4x4 block) -static const uint8_t g_aPartitionTable[3][64][16] = -{ - { // 1 Region case has no subsets (all 0) - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } - }, - - { // BC6H/BC7 Partition Set for 2 Subsets - { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 }, // Shape 0 - { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 }, // Shape 1 - { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 }, // Shape 2 - { 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1 }, // Shape 3 - { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 }, // Shape 4 - { 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, // Shape 5 - { 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, // Shape 6 - { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1 }, // Shape 7 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1 }, // Shape 8 - { 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 9 - { 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, // Shape 10 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1 }, // Shape 11 - { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 12 - { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 13 - { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 14 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 }, // Shape 15 - { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1 }, // Shape 16 - { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, // Shape 17 - { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0 }, // Shape 18 - { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 }, // Shape 19 - { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, // Shape 20 - { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0 }, // Shape 21 - { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 }, // Shape 22 - { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1 }, // Shape 23 - { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 }, // Shape 24 - { 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 }, // Shape 25 - { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 }, // Shape 26 - { 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0 }, // Shape 27 - { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0 }, // Shape 28 - { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, // Shape 29 - { 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0 }, // Shape 30 - { 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0 }, // Shape 31 - - // BC7 Partition Set for 2 Subsets (second-half) - { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 }, // Shape 32 - { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 }, // Shape 33 - { 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0 }, // Shape 34 - { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0 }, // Shape 35 - { 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0 }, // Shape 36 - { 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0 }, // Shape 37 - { 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1 }, // Shape 38 - { 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1 }, // Shape 39 - { 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0 }, // Shape 40 - { 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0 }, // Shape 41 - { 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 }, // Shape 42 - { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0 }, // Shape 43 - { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }, // Shape 44 - { 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1 }, // Shape 45 - { 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1 }, // Shape 46 - { 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 }, // Shape 47 - { 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, // Shape 48 - { 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, // Shape 49 - { 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0 }, // Shape 50 - { 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0 }, // Shape 51 - { 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 }, // Shape 52 - { 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1 }, // Shape 53 - { 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0 }, // Shape 54 - { 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0 }, // Shape 55 - { 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1 }, // Shape 56 - { 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1 }, // Shape 57 - { 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1 }, // Shape 58 - { 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1 }, // Shape 59 - { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 }, // Shape 60 - { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, // Shape 61 - { 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0 }, // Shape 62 - { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1 } // Shape 63 - }, - - { // BC7 Partition Set for 3 Subsets - { 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 1, 2, 2, 2, 2 }, // Shape 0 - { 0, 0, 0, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1 }, // Shape 1 - { 0, 0, 0, 0, 2, 0, 0, 1, 2, 2, 1, 1, 2, 2, 1, 1 }, // Shape 2 - { 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 1, 0, 1, 1, 1 }, // Shape 3 - { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2 }, // Shape 4 - { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 2, 2 }, // Shape 5 - { 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 6 - { 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1 }, // Shape 7 - { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2 }, // Shape 8 - { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2 }, // Shape 9 - { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 10 - { 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2 }, // Shape 11 - { 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2 }, // Shape 12 - { 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2 }, // Shape 13 - { 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2 }, // Shape 14 - { 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0, 2, 2, 2, 0 }, // Shape 15 - { 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2 }, // Shape 16 - { 0, 1, 1, 1, 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0 }, // Shape 17 - { 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2 }, // Shape 18 - { 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1 }, // Shape 19 - { 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2 }, // Shape 20 - { 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 1, 2, 2, 2, 1 }, // Shape 21 - { 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2 }, // Shape 22 - { 0, 0, 0, 0, 1, 1, 0, 0, 2, 2, 1, 0, 2, 2, 1, 0 }, // Shape 23 - { 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1, 0, 0, 0, 0 }, // Shape 24 - { 0, 0, 1, 2, 0, 0, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2 }, // Shape 25 - { 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1, 0, 1, 1, 0 }, // Shape 26 - { 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1 }, // Shape 27 - { 0, 0, 2, 2, 1, 1, 0, 2, 1, 1, 0, 2, 0, 0, 2, 2 }, // Shape 28 - { 0, 1, 1, 0, 0, 1, 1, 0, 2, 0, 0, 2, 2, 2, 2, 2 }, // Shape 29 - { 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1 }, // Shape 30 - { 0, 0, 0, 0, 2, 0, 0, 0, 2, 2, 1, 1, 2, 2, 2, 1 }, // Shape 31 - { 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 2, 2, 2 }, // Shape 32 - { 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 2, 0, 0, 1, 1 }, // Shape 33 - { 0, 0, 1, 1, 0, 0, 1, 2, 0, 0, 2, 2, 0, 2, 2, 2 }, // Shape 34 - { 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0 }, // Shape 35 - { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0 }, // Shape 36 - { 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0 }, // Shape 37 - { 0, 1, 2, 0, 2, 0, 1, 2, 1, 2, 0, 1, 0, 1, 2, 0 }, // Shape 38 - { 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 0, 0, 1, 1 }, // Shape 39 - { 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1 }, // Shape 40 - { 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 41 - { 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1 }, // Shape 42 - { 0, 0, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2, 1, 1, 2, 2 }, // Shape 43 - { 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 1, 1 }, // Shape 44 - { 0, 2, 2, 0, 1, 2, 2, 1, 0, 2, 2, 0, 1, 2, 2, 1 }, // Shape 45 - { 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 1 }, // Shape 46 - { 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1 }, // Shape 47 - { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2 }, // Shape 48 - { 0, 2, 2, 2, 0, 1, 1, 1, 0, 2, 2, 2, 0, 1, 1, 1 }, // Shape 49 - { 0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 0, 2, 1, 1, 1, 2 }, // Shape 50 - { 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2 }, // Shape 51 - { 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2 }, // Shape 52 - { 0, 0, 0, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2 }, // Shape 53 - { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2 }, // Shape 54 - { 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2 }, // Shape 55 - { 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 56 - { 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2 }, // Shape 57 - { 0, 0, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2 }, // Shape 58 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2 }, // Shape 59 - { 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1 }, // Shape 60 - { 0, 2, 2, 2, 1, 2, 2, 2, 0, 2, 2, 2, 1, 2, 2, 2 }, // Shape 61 - { 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 62 - { 0, 1, 1, 1, 2, 0, 1, 1, 2, 2, 0, 1, 2, 2, 2, 0 } // Shape 63 - } -}; - -// Partition, Shape, Fixup -static const uint8_t g_aFixUp[3][64][3] = -{ - { // No fix-ups for 1st subset for BC6H or BC7 - { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, - { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, - { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, - { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, - { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, - { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, - { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, - { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, - { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, - { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, - { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, - { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, - { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, - { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, - { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, - { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0} - }, - - { // BC6H/BC7 Partition Set Fixups for 2 Subsets - { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, - { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, - { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, - { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, - { 0,15, 0}, { 0, 2, 0}, { 0, 8, 0}, { 0, 2, 0}, - { 0, 2, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0,15, 0}, - { 0, 2, 0}, { 0, 8, 0}, { 0, 2, 0}, { 0, 2, 0}, - { 0, 8, 0}, { 0, 8, 0}, { 0, 2, 0}, { 0, 2, 0}, - - // BC7 Partition Set Fixups for 2 Subsets (second-half) - { 0,15, 0}, { 0,15, 0}, { 0, 6, 0}, { 0, 8, 0}, - { 0, 2, 0}, { 0, 8, 0}, { 0,15, 0}, { 0,15, 0}, - { 0, 2, 0}, { 0, 8, 0}, { 0, 2, 0}, { 0, 2, 0}, - { 0, 2, 0}, { 0,15, 0}, { 0,15, 0}, { 0, 6, 0}, - { 0, 6, 0}, { 0, 2, 0}, { 0, 6, 0}, { 0, 8, 0}, - { 0,15, 0}, { 0,15, 0}, { 0, 2, 0}, { 0, 2, 0}, - { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, { 0,15, 0}, - { 0,15, 0}, { 0, 2, 0}, { 0, 2, 0}, { 0,15, 0} - }, - - { // BC7 Partition Set Fixups for 3 Subsets - { 0, 3,15}, { 0, 3, 8}, { 0,15, 8}, { 0,15, 3}, - { 0, 8,15}, { 0, 3,15}, { 0,15, 3}, { 0,15, 8}, - { 0, 8,15}, { 0, 8,15}, { 0, 6,15}, { 0, 6,15}, - { 0, 6,15}, { 0, 5,15}, { 0, 3,15}, { 0, 3, 8}, - { 0, 3,15}, { 0, 3, 8}, { 0, 8,15}, { 0,15, 3}, - { 0, 3,15}, { 0, 3, 8}, { 0, 6,15}, { 0,10, 8}, - { 0, 5, 3}, { 0, 8,15}, { 0, 8, 6}, { 0, 6,10}, - { 0, 8,15}, { 0, 5,15}, { 0,15,10}, { 0,15, 8}, - { 0, 8,15}, { 0,15, 3}, { 0, 3,15}, { 0, 5,10}, - { 0, 6,10}, { 0,10, 8}, { 0, 8, 9}, { 0,15,10}, - { 0,15, 6}, { 0, 3,15}, { 0,15, 8}, { 0, 5,15}, - { 0,15, 3}, { 0,15, 6}, { 0,15, 6}, { 0,15, 8}, - { 0, 3,15}, { 0,15, 3}, { 0, 5,15}, { 0, 5,15}, - { 0, 5,15}, { 0, 8,15}, { 0, 5,15}, { 0,10,15}, - { 0, 5,15}, { 0,10,15}, { 0, 8,15}, { 0,13,15}, - { 0,15, 3}, { 0,12,15}, { 0, 3,15}, { 0, 3, 8} - } -}; + const int g_aWeights2[] = { 0, 21, 43, 64 }; + const int g_aWeights3[] = { 0, 9, 18, 27, 37, 46, 55, 64 }; + const int g_aWeights4[] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 }; +} // BC6H Compression const D3DX_BC6H::ModeDescriptor D3DX_BC6H::ms_aDesc[14][82] = @@ -555,517 +559,532 @@ const D3DX_BC7::ModeInfo D3DX_BC7::ms_aInfo[] = }; -//------------------------------------------------------------------------------------- -// Helper functions -//------------------------------------------------------------------------------------- -inline static bool IsFixUpOffset(_In_range_(0,2) size_t uPartitions, _In_range_(0,63) size_t uShape, _In_range_(0,15) size_t uOffset) +namespace { - assert(uPartitions < 3 && uShape < 64 && uOffset < 16); - _Analysis_assume_(uPartitions < 3 && uShape < 64 && uOffset < 16); - for(size_t p = 0; p <= uPartitions; p++) + //------------------------------------------------------------------------------------- + // Helper functions + //------------------------------------------------------------------------------------- + inline bool IsFixUpOffset(_In_range_(0, 2) size_t uPartitions, _In_range_(0, 63) size_t uShape, _In_range_(0, 15) size_t uOffset) { - if(uOffset == g_aFixUp[uPartitions][uShape][p]) + assert(uPartitions < 3 && uShape < 64 && uOffset < 16); + _Analysis_assume_(uPartitions < 3 && uShape < 64 && uOffset < 16); + for (size_t p = 0; p <= uPartitions; p++) { - return true; + if (uOffset == g_aFixUp[uPartitions][uShape][p]) + { + return true; + } + } + return false; + } + + inline void TransformForward(_Inout_updates_all_(BC6H_MAX_REGIONS) INTEndPntPair aEndPts[]) + { + aEndPts[0].B -= aEndPts[0].A; + aEndPts[1].A -= aEndPts[0].A; + aEndPts[1].B -= aEndPts[0].A; + } + + inline void TransformInverse(_Inout_updates_all_(BC6H_MAX_REGIONS) INTEndPntPair aEndPts[], _In_ const LDRColorA& Prec, _In_ bool bSigned) + { + INTColor WrapMask((1 << Prec.r) - 1, (1 << Prec.g) - 1, (1 << Prec.b) - 1); + aEndPts[0].B += aEndPts[0].A; aEndPts[0].B &= WrapMask; + aEndPts[1].A += aEndPts[0].A; aEndPts[1].A &= WrapMask; + aEndPts[1].B += aEndPts[0].A; aEndPts[1].B &= WrapMask; + if (bSigned) + { + aEndPts[0].B.SignExtend(Prec); + aEndPts[1].A.SignExtend(Prec); + aEndPts[1].B.SignExtend(Prec); } } - return false; -} -inline static void TransformForward(_Inout_updates_all_(BC6H_MAX_REGIONS) INTEndPntPair aEndPts[]) -{ - aEndPts[0].B -= aEndPts[0].A; - aEndPts[1].A -= aEndPts[0].A; - aEndPts[1].B -= aEndPts[0].A; -} - -inline static void TransformInverse(_Inout_updates_all_(BC6H_MAX_REGIONS) INTEndPntPair aEndPts[], _In_ const LDRColorA& Prec, _In_ bool bSigned) -{ - INTColor WrapMask((1 << Prec.r) - 1, (1 << Prec.g) - 1, (1 << Prec.b) - 1); - aEndPts[0].B += aEndPts[0].A; aEndPts[0].B &= WrapMask; - aEndPts[1].A += aEndPts[0].A; aEndPts[1].A &= WrapMask; - aEndPts[1].B += aEndPts[0].A; aEndPts[1].B &= WrapMask; - if(bSigned) + inline float Norm(_In_ const INTColor& a, _In_ const INTColor& b) { - aEndPts[0].B.SignExtend(Prec); - aEndPts[1].A.SignExtend(Prec); - aEndPts[1].B.SignExtend(Prec); - } -} - -inline static float Norm(_In_ const INTColor& a, _In_ const INTColor& b) -{ - float dr = float(a.r) - float(b.r); - float dg = float(a.g) - float(b.g); - float db = float(a.b) - float(b.b); - return dr * dr + dg * dg + db * db; -} - -// return # of bits needed to store n. handle signed or unsigned cases properly -inline static int NBits(_In_ int n, _In_ bool bIsSigned) -{ - int nb; - if(n == 0) - { - return 0; // no bits needed for 0, signed or not - } - else if(n > 0) - { - for(nb = 0; n; ++nb, n >>= 1); - return nb + (bIsSigned ? 1 : 0); - } - else - { - assert(bIsSigned); - for(nb = 0; n < -1; ++nb, n >>= 1) ; - return nb + 1; - } -} - - -//------------------------------------------------------------------------------------- -static float OptimizeRGB(_In_reads_(NUM_PIXELS_PER_BLOCK) const HDRColorA* const pPoints, - _Out_ HDRColorA* pX, _Out_ HDRColorA* pY, - _In_ size_t cSteps, _In_ size_t cPixels, _In_reads_(cPixels) const size_t* pIndex) -{ - float fError = FLT_MAX; - const float *pC = (3 == cSteps) ? pC3 : pC4; - const float *pD = (3 == cSteps) ? pD3 : pD4; - - // Find Min and Max points, as starting point - HDRColorA X(1.0f, 1.0f, 1.0f, 0.0f); - HDRColorA Y(0.0f, 0.0f, 0.0f, 0.0f); - - for(size_t iPoint = 0; iPoint < cPixels; iPoint++) - { - if(pPoints[pIndex[iPoint]].r < X.r) X.r = pPoints[pIndex[iPoint]].r; - if(pPoints[pIndex[iPoint]].g < X.g) X.g = pPoints[pIndex[iPoint]].g; - if(pPoints[pIndex[iPoint]].b < X.b) X.b = pPoints[pIndex[iPoint]].b; - if(pPoints[pIndex[iPoint]].r > Y.r) Y.r = pPoints[pIndex[iPoint]].r; - if(pPoints[pIndex[iPoint]].g > Y.g) Y.g = pPoints[pIndex[iPoint]].g; - if(pPoints[pIndex[iPoint]].b > Y.b) Y.b = pPoints[pIndex[iPoint]].b; + float dr = float(a.r) - float(b.r); + float dg = float(a.g) - float(b.g); + float db = float(a.b) - float(b.b); + return dr * dr + dg * dg + db * db; } - // Diagonal axis - HDRColorA AB; - AB.r = Y.r - X.r; - AB.g = Y.g - X.g; - AB.b = Y.b - X.b; - - float fAB = AB.r * AB.r + AB.g * AB.g + AB.b * AB.b; - - // Single color block.. no need to root-find - if(fAB < FLT_MIN) + // return # of bits needed to store n. handle signed or unsigned cases properly + inline int NBits(_In_ int n, _In_ bool bIsSigned) { + int nb; + if (n == 0) + { + return 0; // no bits needed for 0, signed or not + } + else if (n > 0) + { + for (nb = 0; n; ++nb, n >>= 1); + return nb + (bIsSigned ? 1 : 0); + } + else + { + assert(bIsSigned); + for (nb = 0; n < -1; ++nb, n >>= 1); + return nb + 1; + } + } + + + //------------------------------------------------------------------------------------- + float OptimizeRGB( + _In_reads_(NUM_PIXELS_PER_BLOCK) const HDRColorA* const pPoints, + _Out_ HDRColorA* pX, + _Out_ HDRColorA* pY, + size_t cSteps, + size_t cPixels, + _In_reads_(cPixels) const size_t* pIndex) + { + float fError = FLT_MAX; + const float *pC = (3 == cSteps) ? pC3 : pC4; + const float *pD = (3 == cSteps) ? pD3 : pD4; + + // Find Min and Max points, as starting point + HDRColorA X(1.0f, 1.0f, 1.0f, 0.0f); + HDRColorA Y(0.0f, 0.0f, 0.0f, 0.0f); + + for (size_t iPoint = 0; iPoint < cPixels; iPoint++) + { + if (pPoints[pIndex[iPoint]].r < X.r) X.r = pPoints[pIndex[iPoint]].r; + if (pPoints[pIndex[iPoint]].g < X.g) X.g = pPoints[pIndex[iPoint]].g; + if (pPoints[pIndex[iPoint]].b < X.b) X.b = pPoints[pIndex[iPoint]].b; + if (pPoints[pIndex[iPoint]].r > Y.r) Y.r = pPoints[pIndex[iPoint]].r; + if (pPoints[pIndex[iPoint]].g > Y.g) Y.g = pPoints[pIndex[iPoint]].g; + if (pPoints[pIndex[iPoint]].b > Y.b) Y.b = pPoints[pIndex[iPoint]].b; + } + + // Diagonal axis + HDRColorA AB; + AB.r = Y.r - X.r; + AB.g = Y.g - X.g; + AB.b = Y.b - X.b; + + float fAB = AB.r * AB.r + AB.g * AB.g + AB.b * AB.b; + + // Single color block.. no need to root-find + if (fAB < FLT_MIN) + { + pX->r = X.r; pX->g = X.g; pX->b = X.b; + pY->r = Y.r; pY->g = Y.g; pY->b = Y.b; + return 0.0f; + } + + // Try all four axis directions, to determine which diagonal best fits data + float fABInv = 1.0f / fAB; + + HDRColorA Dir; + Dir.r = AB.r * fABInv; + Dir.g = AB.g * fABInv; + Dir.b = AB.b * fABInv; + + HDRColorA Mid; + Mid.r = (X.r + Y.r) * 0.5f; + Mid.g = (X.g + Y.g) * 0.5f; + Mid.b = (X.b + Y.b) * 0.5f; + + float fDir[4]; + fDir[0] = fDir[1] = fDir[2] = fDir[3] = 0.0f; + + for (size_t iPoint = 0; iPoint < cPixels; iPoint++) + { + HDRColorA Pt; + Pt.r = (pPoints[pIndex[iPoint]].r - Mid.r) * Dir.r; + Pt.g = (pPoints[pIndex[iPoint]].g - Mid.g) * Dir.g; + Pt.b = (pPoints[pIndex[iPoint]].b - Mid.b) * Dir.b; + + float f; + f = Pt.r + Pt.g + Pt.b; fDir[0] += f * f; + f = Pt.r + Pt.g - Pt.b; fDir[1] += f * f; + f = Pt.r - Pt.g + Pt.b; fDir[2] += f * f; + f = Pt.r - Pt.g - Pt.b; fDir[3] += f * f; + } + + float fDirMax = fDir[0]; + size_t iDirMax = 0; + + for (size_t iDir = 1; iDir < 4; iDir++) + { + if (fDir[iDir] > fDirMax) + { + fDirMax = fDir[iDir]; + iDirMax = iDir; + } + } + + if (iDirMax & 2) std::swap(X.g, Y.g); + if (iDirMax & 1) std::swap(X.b, Y.b); + + // Two color block.. no need to root-find + if (fAB < 1.0f / 4096.0f) + { + pX->r = X.r; pX->g = X.g; pX->b = X.b; + pY->r = Y.r; pY->g = Y.g; pY->b = Y.b; + return 0.0f; + } + + // Use Newton's Method to find local minima of sum-of-squares error. + float fSteps = (float)(cSteps - 1); + + for (size_t iIteration = 0; iIteration < 8; iIteration++) + { + // Calculate new steps + HDRColorA pSteps[4] = {}; + + for (size_t iStep = 0; iStep < cSteps; iStep++) + { + pSteps[iStep].r = X.r * pC[iStep] + Y.r * pD[iStep]; + pSteps[iStep].g = X.g * pC[iStep] + Y.g * pD[iStep]; + pSteps[iStep].b = X.b * pC[iStep] + Y.b * pD[iStep]; + } + + // Calculate color direction + Dir.r = Y.r - X.r; + Dir.g = Y.g - X.g; + Dir.b = Y.b - X.b; + + float fLen = (Dir.r * Dir.r + Dir.g * Dir.g + Dir.b * Dir.b); + + if (fLen < (1.0f / 4096.0f)) + break; + + float fScale = fSteps / fLen; + + Dir.r *= fScale; + Dir.g *= fScale; + Dir.b *= fScale; + + // Evaluate function, and derivatives + float d2X = 0.0f, d2Y = 0.0f; + HDRColorA dX(0.0f, 0.0f, 0.0f, 0.0f), dY(0.0f, 0.0f, 0.0f, 0.0f); + + for (size_t iPoint = 0; iPoint < cPixels; iPoint++) + { + float fDot = (pPoints[pIndex[iPoint]].r - X.r) * Dir.r + + (pPoints[pIndex[iPoint]].g - X.g) * Dir.g + + (pPoints[pIndex[iPoint]].b - X.b) * Dir.b; + + size_t iStep; + if (fDot <= 0.0f) + iStep = 0; + if (fDot >= fSteps) + iStep = cSteps - 1; + else + iStep = size_t(fDot + 0.5f); + + HDRColorA Diff; + Diff.r = pSteps[iStep].r - pPoints[pIndex[iPoint]].r; + Diff.g = pSteps[iStep].g - pPoints[pIndex[iPoint]].g; + Diff.b = pSteps[iStep].b - pPoints[pIndex[iPoint]].b; + + float fC = pC[iStep] * (1.0f / 8.0f); + float fD = pD[iStep] * (1.0f / 8.0f); + + d2X += fC * pC[iStep]; + dX.r += fC * Diff.r; + dX.g += fC * Diff.g; + dX.b += fC * Diff.b; + + d2Y += fD * pD[iStep]; + dY.r += fD * Diff.r; + dY.g += fD * Diff.g; + dY.b += fD * Diff.b; + } + + // Move endpoints + if (d2X > 0.0f) + { + float f = -1.0f / d2X; + + X.r += dX.r * f; + X.g += dX.g * f; + X.b += dX.b * f; + } + + if (d2Y > 0.0f) + { + float f = -1.0f / d2Y; + + Y.r += dY.r * f; + Y.g += dY.g * f; + Y.b += dY.b * f; + } + + if ((dX.r * dX.r < fEpsilon) && (dX.g * dX.g < fEpsilon) && (dX.b * dX.b < fEpsilon) && + (dY.r * dY.r < fEpsilon) && (dY.g * dY.g < fEpsilon) && (dY.b * dY.b < fEpsilon)) + { + break; + } + } + pX->r = X.r; pX->g = X.g; pX->b = X.b; pY->r = Y.r; pY->g = Y.g; pY->b = Y.b; - return 0.0f; + return fError; } - // Try all four axis directions, to determine which diagonal best fits data - float fABInv = 1.0f / fAB; - HDRColorA Dir; - Dir.r = AB.r * fABInv; - Dir.g = AB.g * fABInv; - Dir.b = AB.b * fABInv; - - HDRColorA Mid; - Mid.r = (X.r + Y.r) * 0.5f; - Mid.g = (X.g + Y.g) * 0.5f; - Mid.b = (X.b + Y.b) * 0.5f; - - float fDir[4]; - fDir[0] = fDir[1] = fDir[2] = fDir[3] = 0.0f; - - for(size_t iPoint = 0; iPoint < cPixels; iPoint++) + //------------------------------------------------------------------------------------- + float OptimizeRGBA( + _In_reads_(NUM_PIXELS_PER_BLOCK) const HDRColorA* const pPoints, + _Out_ HDRColorA* pX, + _Out_ HDRColorA* pY, + size_t cSteps, + size_t cPixels, + _In_reads_(cPixels) const size_t* pIndex) { - HDRColorA Pt; - Pt.r = (pPoints[pIndex[iPoint]].r - Mid.r) * Dir.r; - Pt.g = (pPoints[pIndex[iPoint]].g - Mid.g) * Dir.g; - Pt.b = (pPoints[pIndex[iPoint]].b - Mid.b) * Dir.b; + float fError = FLT_MAX; + const float *pC = (3 == cSteps) ? pC3 : pC4; + const float *pD = (3 == cSteps) ? pD3 : pD4; - float f; - f = Pt.r + Pt.g + Pt.b; fDir[0] += f * f; - f = Pt.r + Pt.g - Pt.b; fDir[1] += f * f; - f = Pt.r - Pt.g + Pt.b; fDir[2] += f * f; - f = Pt.r - Pt.g - Pt.b; fDir[3] += f * f; - } + // Find Min and Max points, as starting point + HDRColorA X(1.0f, 1.0f, 1.0f, 1.0f); + HDRColorA Y(0.0f, 0.0f, 0.0f, 0.0f); - float fDirMax = fDir[0]; - size_t iDirMax = 0; - - for(size_t iDir = 1; iDir < 4; iDir++) - { - if(fDir[iDir] > fDirMax) + for (size_t iPoint = 0; iPoint < cPixels; iPoint++) { - fDirMax = fDir[iDir]; - iDirMax = iDir; - } - } - - if(iDirMax & 2) std::swap( X.g, Y.g ); - if(iDirMax & 1) std::swap( X.b, Y.b ); - - // Two color block.. no need to root-find - if(fAB < 1.0f / 4096.0f) - { - pX->r = X.r; pX->g = X.g; pX->b = X.b; - pY->r = Y.r; pY->g = Y.g; pY->b = Y.b; - return 0.0f; - } - - // Use Newton's Method to find local minima of sum-of-squares error. - float fSteps = (float) (cSteps - 1); - - for(size_t iIteration = 0; iIteration < 8; iIteration++) - { - // Calculate new steps - HDRColorA pSteps[4] = {}; - - for(size_t iStep = 0; iStep < cSteps; iStep++) - { - pSteps[iStep].r = X.r * pC[iStep] + Y.r * pD[iStep]; - pSteps[iStep].g = X.g * pC[iStep] + Y.g * pD[iStep]; - pSteps[iStep].b = X.b * pC[iStep] + Y.b * pD[iStep]; + if (pPoints[pIndex[iPoint]].r < X.r) X.r = pPoints[pIndex[iPoint]].r; + if (pPoints[pIndex[iPoint]].g < X.g) X.g = pPoints[pIndex[iPoint]].g; + if (pPoints[pIndex[iPoint]].b < X.b) X.b = pPoints[pIndex[iPoint]].b; + if (pPoints[pIndex[iPoint]].a < X.a) X.a = pPoints[pIndex[iPoint]].a; + if (pPoints[pIndex[iPoint]].r > Y.r) Y.r = pPoints[pIndex[iPoint]].r; + if (pPoints[pIndex[iPoint]].g > Y.g) Y.g = pPoints[pIndex[iPoint]].g; + if (pPoints[pIndex[iPoint]].b > Y.b) Y.b = pPoints[pIndex[iPoint]].b; + if (pPoints[pIndex[iPoint]].a > Y.a) Y.a = pPoints[pIndex[iPoint]].a; } - // Calculate color direction - Dir.r = Y.r - X.r; - Dir.g = Y.g - X.g; - Dir.b = Y.b - X.b; + // Diagonal axis + HDRColorA AB = Y - X; + float fAB = AB * AB; - float fLen = (Dir.r * Dir.r + Dir.g * Dir.g + Dir.b * Dir.b); - - if(fLen < (1.0f / 4096.0f)) - break; - - float fScale = fSteps / fLen; - - Dir.r *= fScale; - Dir.g *= fScale; - Dir.b *= fScale; - - // Evaluate function, and derivatives - float d2X = 0.0f, d2Y = 0.0f; - HDRColorA dX(0.0f, 0.0f, 0.0f, 0.0f), dY(0.0f, 0.0f, 0.0f, 0.0f); - - for(size_t iPoint = 0; iPoint < cPixels; iPoint++) + // Single color block.. no need to root-find + if (fAB < FLT_MIN) { - float fDot = (pPoints[pIndex[iPoint]].r - X.r) * Dir.r + - (pPoints[pIndex[iPoint]].g - X.g) * Dir.g + - (pPoints[pIndex[iPoint]].b - X.b) * Dir.b; - - size_t iStep; - if(fDot <= 0.0f) - iStep = 0; - if(fDot >= fSteps) - iStep = cSteps - 1; - else - iStep = size_t(fDot + 0.5f); - - HDRColorA Diff; - Diff.r = pSteps[iStep].r - pPoints[pIndex[iPoint]].r; - Diff.g = pSteps[iStep].g - pPoints[pIndex[iPoint]].g; - Diff.b = pSteps[iStep].b - pPoints[pIndex[iPoint]].b; - - float fC = pC[iStep] * (1.0f / 8.0f); - float fD = pD[iStep] * (1.0f / 8.0f); - - d2X += fC * pC[iStep]; - dX.r += fC * Diff.r; - dX.g += fC * Diff.g; - dX.b += fC * Diff.b; - - d2Y += fD * pD[iStep]; - dY.r += fD * Diff.r; - dY.g += fD * Diff.g; - dY.b += fD * Diff.b; + *pX = X; + *pY = Y; + return 0.0f; } - // Move endpoints - if(d2X > 0.0f) - { - float f = -1.0f / d2X; + // Try all four axis directions, to determine which diagonal best fits data + float fABInv = 1.0f / fAB; + HDRColorA Dir = AB * fABInv; + HDRColorA Mid = (X + Y) * 0.5f; - X.r += dX.r * f; - X.g += dX.g * f; - X.b += dX.b * f; + float fDir[8]; + fDir[0] = fDir[1] = fDir[2] = fDir[3] = fDir[4] = fDir[5] = fDir[6] = fDir[7] = 0.0f; + + for (size_t iPoint = 0; iPoint < cPixels; iPoint++) + { + HDRColorA Pt; + Pt.r = (pPoints[pIndex[iPoint]].r - Mid.r) * Dir.r; + Pt.g = (pPoints[pIndex[iPoint]].g - Mid.g) * Dir.g; + Pt.b = (pPoints[pIndex[iPoint]].b - Mid.b) * Dir.b; + Pt.a = (pPoints[pIndex[iPoint]].a - Mid.a) * Dir.a; + + float f; + f = Pt.r + Pt.g + Pt.b + Pt.a; fDir[0] += f * f; + f = Pt.r + Pt.g + Pt.b - Pt.a; fDir[1] += f * f; + f = Pt.r + Pt.g - Pt.b + Pt.a; fDir[2] += f * f; + f = Pt.r + Pt.g - Pt.b - Pt.a; fDir[3] += f * f; + f = Pt.r - Pt.g + Pt.b + Pt.a; fDir[4] += f * f; + f = Pt.r - Pt.g + Pt.b - Pt.a; fDir[5] += f * f; + f = Pt.r - Pt.g - Pt.b + Pt.a; fDir[6] += f * f; + f = Pt.r - Pt.g - Pt.b - Pt.a; fDir[7] += f * f; } - if(d2Y > 0.0f) - { - float f = -1.0f / d2Y; + float fDirMax = fDir[0]; + size_t iDirMax = 0; - Y.r += dY.r * f; - Y.g += dY.g * f; - Y.b += dY.b * f; + for (size_t iDir = 1; iDir < 8; iDir++) + { + if (fDir[iDir] > fDirMax) + { + fDirMax = fDir[iDir]; + iDirMax = iDir; + } } - if((dX.r * dX.r < fEpsilon) && (dX.g * dX.g < fEpsilon) && (dX.b * dX.b < fEpsilon) && - (dY.r * dY.r < fEpsilon) && (dY.g * dY.g < fEpsilon) && (dY.b * dY.b < fEpsilon)) + if (iDirMax & 4) std::swap(X.g, Y.g); + if (iDirMax & 2) std::swap(X.b, Y.b); + if (iDirMax & 1) std::swap(X.a, Y.a); + + // Two color block.. no need to root-find + if (fAB < 1.0f / 4096.0f) { - break; + *pX = X; + *pY = Y; + return 0.0f; } - } - pX->r = X.r; pX->g = X.g; pX->b = X.b; - pY->r = Y.r; pY->g = Y.g; pY->b = Y.b; - return fError; -} + // Use Newton's Method to find local minima of sum-of-squares error. + float fSteps = (float)(cSteps - 1); + for (size_t iIteration = 0; iIteration < 8 && fError > 0.0f; iIteration++) + { + // Calculate new steps + HDRColorA pSteps[BC7_MAX_INDICES]; -//------------------------------------------------------------------------------------- -static float OptimizeRGBA(_In_reads_(NUM_PIXELS_PER_BLOCK) const HDRColorA* const pPoints, - _Out_ HDRColorA* pX, _Out_ HDRColorA* pY, - _In_ size_t cSteps, _In_ size_t cPixels, _In_reads_(cPixels) const size_t* pIndex) -{ - float fError = FLT_MAX; - const float *pC = (3 == cSteps) ? pC3 : pC4; - const float *pD = (3 == cSteps) ? pD3 : pD4; + LDRColorA lX, lY; + lX = (X * 255.0f).ToLDRColorA(); + lY = (Y * 255.0f).ToLDRColorA(); - // Find Min and Max points, as starting point - HDRColorA X(1.0f, 1.0f, 1.0f, 1.0f); - HDRColorA Y(0.0f, 0.0f, 0.0f, 0.0f); + for (size_t iStep = 0; iStep < cSteps; iStep++) + { + pSteps[iStep] = X * pC[iStep] + Y * pD[iStep]; + //LDRColorA::Interpolate(lX, lY, i, i, wcprec, waprec, aSteps[i]); + } - for(size_t iPoint = 0; iPoint < cPixels; iPoint++) - { - if(pPoints[pIndex[iPoint]].r < X.r) X.r = pPoints[pIndex[iPoint]].r; - if(pPoints[pIndex[iPoint]].g < X.g) X.g = pPoints[pIndex[iPoint]].g; - if(pPoints[pIndex[iPoint]].b < X.b) X.b = pPoints[pIndex[iPoint]].b; - if(pPoints[pIndex[iPoint]].a < X.a) X.a = pPoints[pIndex[iPoint]].a; - if(pPoints[pIndex[iPoint]].r > Y.r) Y.r = pPoints[pIndex[iPoint]].r; - if(pPoints[pIndex[iPoint]].g > Y.g) Y.g = pPoints[pIndex[iPoint]].g; - if(pPoints[pIndex[iPoint]].b > Y.b) Y.b = pPoints[pIndex[iPoint]].b; - if(pPoints[pIndex[iPoint]].a > Y.a) Y.a = pPoints[pIndex[iPoint]].a; - } + // Calculate color direction + Dir = Y - X; + float fLen = Dir * Dir; + if (fLen < (1.0f / 4096.0f)) + break; - // Diagonal axis - HDRColorA AB = Y - X; - float fAB = AB * AB; + float fScale = fSteps / fLen; + Dir *= fScale; + + // Evaluate function, and derivatives + float d2X = 0.0f, d2Y = 0.0f; + HDRColorA dX(0.0f, 0.0f, 0.0f, 0.0f), dY(0.0f, 0.0f, 0.0f, 0.0f); + + for (size_t iPoint = 0; iPoint < cPixels; ++iPoint) + { + float fDot = (pPoints[pIndex[iPoint]] - X) * Dir; + size_t iStep; + if (fDot <= 0.0f) + iStep = 0; + if (fDot >= fSteps) + iStep = cSteps - 1; + else + iStep = size_t(fDot + 0.5f); + + HDRColorA Diff = pSteps[iStep] - pPoints[pIndex[iPoint]]; + float fC = pC[iStep] * (1.0f / 8.0f); + float fD = pD[iStep] * (1.0f / 8.0f); + + d2X += fC * pC[iStep]; + dX += Diff * fC; + + d2Y += fD * pD[iStep]; + dY += Diff * fD; + } + + // Move endpoints + if (d2X > 0.0f) + { + float f = -1.0f / d2X; + X += dX * f; + } + + if (d2Y > 0.0f) + { + float f = -1.0f / d2Y; + Y += dY * f; + } + + if ((dX * dX < fEpsilon) && (dY * dY < fEpsilon)) + break; + } - // Single color block.. no need to root-find - if(fAB < FLT_MIN) - { *pX = X; *pY = Y; - return 0.0f; + return fError; } - // Try all four axis directions, to determine which diagonal best fits data - float fABInv = 1.0f / fAB; - HDRColorA Dir = AB * fABInv; - HDRColorA Mid = (X + Y) * 0.5f; - float fDir[8]; - fDir[0] = fDir[1] = fDir[2] = fDir[3] = fDir[4] = fDir[5] = fDir[6] = fDir[7] = 0.0f; - - for(size_t iPoint = 0; iPoint < cPixels; iPoint++) + //------------------------------------------------------------------------------------- + float ComputeError( + _Inout_ const LDRColorA& pixel, + _In_reads_(1 << uIndexPrec) const LDRColorA aPalette[], + uint8_t uIndexPrec, + uint8_t uIndexPrec2, + _Out_opt_ size_t* pBestIndex = nullptr, + _Out_opt_ size_t* pBestIndex2 = nullptr) { - HDRColorA Pt; - Pt.r = (pPoints[pIndex[iPoint]].r - Mid.r) * Dir.r; - Pt.g = (pPoints[pIndex[iPoint]].g - Mid.g) * Dir.g; - Pt.b = (pPoints[pIndex[iPoint]].b - Mid.b) * Dir.b; - Pt.a = (pPoints[pIndex[iPoint]].a - Mid.a) * Dir.a; + const size_t uNumIndices = size_t(1) << uIndexPrec; + const size_t uNumIndices2 = size_t(1) << uIndexPrec2; + float fTotalErr = 0; + float fBestErr = FLT_MAX; - float f; - f = Pt.r + Pt.g + Pt.b + Pt.a; fDir[0] += f * f; - f = Pt.r + Pt.g + Pt.b - Pt.a; fDir[1] += f * f; - f = Pt.r + Pt.g - Pt.b + Pt.a; fDir[2] += f * f; - f = Pt.r + Pt.g - Pt.b - Pt.a; fDir[3] += f * f; - f = Pt.r - Pt.g + Pt.b + Pt.a; fDir[4] += f * f; - f = Pt.r - Pt.g + Pt.b - Pt.a; fDir[5] += f * f; - f = Pt.r - Pt.g - Pt.b + Pt.a; fDir[6] += f * f; - f = Pt.r - Pt.g - Pt.b - Pt.a; fDir[7] += f * f; - } + if (pBestIndex) + *pBestIndex = 0; + if (pBestIndex2) + *pBestIndex2 = 0; - float fDirMax = fDir[0]; - size_t iDirMax = 0; + XMVECTOR vpixel = XMLoadUByte4(reinterpret_cast(&pixel)); - for(size_t iDir = 1; iDir < 8; iDir++) - { - if(fDir[iDir] > fDirMax) + if (uIndexPrec2 == 0) { - fDirMax = fDir[iDir]; - iDirMax = iDir; - } - } - - if(iDirMax & 4) std::swap(X.g, Y.g); - if(iDirMax & 2) std::swap(X.b, Y.b); - if(iDirMax & 1) std::swap(X.a, Y.a); - - // Two color block.. no need to root-find - if(fAB < 1.0f / 4096.0f) - { - *pX = X; - *pY = Y; - return 0.0f; - } - - // Use Newton's Method to find local minima of sum-of-squares error. - float fSteps = (float) (cSteps - 1); - - for(size_t iIteration = 0; iIteration < 8 && fError > 0.0f; iIteration++) - { - // Calculate new steps - HDRColorA pSteps[BC7_MAX_INDICES]; - - LDRColorA lX, lY; - lX = (X * 255.0f).ToLDRColorA(); - lY = (Y * 255.0f).ToLDRColorA(); - - for(size_t iStep = 0; iStep < cSteps; iStep++) - { - pSteps[iStep] = X * pC[iStep] + Y * pD[iStep]; - //LDRColorA::Interpolate(lX, lY, i, i, wcprec, waprec, aSteps[i]); - } - - // Calculate color direction - Dir = Y - X; - float fLen = Dir * Dir; - if(fLen < (1.0f / 4096.0f)) - break; - - float fScale = fSteps / fLen; - Dir *= fScale; - - // Evaluate function, and derivatives - float d2X = 0.0f, d2Y = 0.0f; - HDRColorA dX(0.0f, 0.0f, 0.0f, 0.0f), dY(0.0f, 0.0f, 0.0f, 0.0f); - - for(size_t iPoint = 0; iPoint < cPixels; ++iPoint) - { - float fDot = (pPoints[pIndex[iPoint]] - X) * Dir; - size_t iStep; - if(fDot <= 0.0f) - iStep = 0; - if(fDot >= fSteps) - iStep = cSteps - 1; - else - iStep = size_t(fDot + 0.5f); - - HDRColorA Diff = pSteps[iStep] - pPoints[pIndex[iPoint]]; - float fC = pC[iStep] * (1.0f / 8.0f); - float fD = pD[iStep] * (1.0f / 8.0f); - - d2X += fC * pC[iStep]; - dX += Diff * fC; - - d2Y += fD * pD[iStep]; - dY += Diff * fD; - } - - // Move endpoints - if(d2X > 0.0f) - { - float f = -1.0f / d2X; - X += dX * f; - } - - if(d2Y > 0.0f) - { - float f = -1.0f / d2Y; - Y += dY * f; - } - - if((dX * dX < fEpsilon) && (dY * dY < fEpsilon)) - break; - } - - *pX = X; - *pY = Y; - return fError; -} - - -//------------------------------------------------------------------------------------- - -static float ComputeError(_Inout_ const LDRColorA& pixel, _In_reads_(1 << uIndexPrec) const LDRColorA aPalette[], - _In_ uint8_t uIndexPrec, _In_ uint8_t uIndexPrec2, _Out_opt_ size_t* pBestIndex = nullptr, _Out_opt_ size_t* pBestIndex2 = nullptr) -{ - const size_t uNumIndices = size_t(1) << uIndexPrec; - const size_t uNumIndices2 = size_t(1) << uIndexPrec2; - float fTotalErr = 0; - float fBestErr = FLT_MAX; - - if(pBestIndex) - *pBestIndex = 0; - if(pBestIndex2) - *pBestIndex2 = 0; - - XMVECTOR vpixel = XMLoadUByte4( reinterpret_cast( &pixel ) ); - - if(uIndexPrec2 == 0) - { - for(register size_t i = 0; i < uNumIndices && fBestErr > 0; i++) - { - XMVECTOR tpixel = XMLoadUByte4( reinterpret_cast( &aPalette[i] ) ); - // Compute ErrorMetric - tpixel = XMVectorSubtract( vpixel, tpixel ); - float fErr = XMVectorGetX( XMVector4Dot( tpixel, tpixel ) ); - if(fErr > fBestErr) // error increased, so we're done searching - break; - if(fErr < fBestErr) + for (register size_t i = 0; i < uNumIndices && fBestErr > 0; i++) { - fBestErr = fErr; - if(pBestIndex) - *pBestIndex = i; + XMVECTOR tpixel = XMLoadUByte4(reinterpret_cast(&aPalette[i])); + // Compute ErrorMetric + tpixel = XMVectorSubtract(vpixel, tpixel); + float fErr = XMVectorGetX(XMVector4Dot(tpixel, tpixel)); + if (fErr > fBestErr) // error increased, so we're done searching + break; + if (fErr < fBestErr) + { + fBestErr = fErr; + if (pBestIndex) + *pBestIndex = i; + } } + fTotalErr += fBestErr; } - fTotalErr += fBestErr; - } - else - { - for(register size_t i = 0; i < uNumIndices && fBestErr > 0; i++) + else { - XMVECTOR tpixel = XMLoadUByte4( reinterpret_cast( &aPalette[i] ) ); - // Compute ErrorMetricRGB - tpixel = XMVectorSubtract( vpixel, tpixel ); - float fErr = XMVectorGetX( XMVector3Dot( tpixel, tpixel ) ); - if(fErr > fBestErr) // error increased, so we're done searching - break; - if(fErr < fBestErr) + for (register size_t i = 0; i < uNumIndices && fBestErr > 0; i++) { - fBestErr = fErr; - if(pBestIndex) - *pBestIndex = i; + XMVECTOR tpixel = XMLoadUByte4(reinterpret_cast(&aPalette[i])); + // Compute ErrorMetricRGB + tpixel = XMVectorSubtract(vpixel, tpixel); + float fErr = XMVectorGetX(XMVector3Dot(tpixel, tpixel)); + if (fErr > fBestErr) // error increased, so we're done searching + break; + if (fErr < fBestErr) + { + fBestErr = fErr; + if (pBestIndex) + *pBestIndex = i; + } } - } - fTotalErr += fBestErr; - fBestErr = FLT_MAX; - for(register size_t i = 0; i < uNumIndices2 && fBestErr > 0; i++) - { - // Compute ErrorMetricAlpha - float ea = float(pixel.a) - float(aPalette[i].a); - float fErr = ea*ea; - if(fErr > fBestErr) // error increased, so we're done searching - break; - if(fErr < fBestErr) + fTotalErr += fBestErr; + fBestErr = FLT_MAX; + for (register size_t i = 0; i < uNumIndices2 && fBestErr > 0; i++) { - fBestErr = fErr; - if(pBestIndex2) - *pBestIndex2 = i; + // Compute ErrorMetricAlpha + float ea = float(pixel.a) - float(aPalette[i].a); + float fErr = ea*ea; + if (fErr > fBestErr) // error increased, so we're done searching + break; + if (fErr < fBestErr) + { + fBestErr = fErr; + if (pBestIndex2) + *pBestIndex2 = i; + } } + fTotalErr += fBestErr; } - fTotalErr += fBestErr; + + return fTotalErr; } - return fTotalErr; -} - -inline static void FillWithErrorColors( _Out_writes_(NUM_PIXELS_PER_BLOCK) HDRColorA* pOut ) -{ - for(size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + void FillWithErrorColors(_Out_writes_(NUM_PIXELS_PER_BLOCK) HDRColorA* pOut) { + for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + { #ifdef _DEBUG - // Use Magenta in debug as a highly-visible error color - pOut[i] = HDRColorA(1.0f, 0.0f, 1.0f, 1.0f); + // Use Magenta in debug as a highly-visible error color + pOut[i] = HDRColorA(1.0f, 0.0f, 1.0f, 1.0f); #else - // In production use, default to black - pOut[i] = HDRColorA(0.0f, 0.0f, 0.0f, 1.0f); + // In production use, default to black + pOut[i] = HDRColorA(0.0f, 0.0f, 0.0f, 1.0f); #endif + } } } @@ -1076,19 +1095,19 @@ inline static void FillWithErrorColors( _Out_writes_(NUM_PIXELS_PER_BLOCK) HDRCo _Use_decl_annotations_ void D3DX_BC6H::Decode(bool bSigned, HDRColorA* pOut) const { - assert(pOut ); + assert(pOut); size_t uStartBit = 0; uint8_t uMode = GetBits(uStartBit, 2); - if(uMode != 0x00 && uMode != 0x01) + if (uMode != 0x00 && uMode != 0x01) { uMode = (GetBits(uStartBit, 3) << 2) | uMode; } - assert( uMode < 32 ); - _Analysis_assume_( uMode < 32 ); + assert(uMode < 32); + _Analysis_assume_(uMode < 32); - if ( ms_aModeToInfo[uMode] >= 0 ) + if (ms_aModeToInfo[uMode] >= 0) { assert(ms_aModeToInfo[uMode] < ARRAYSIZE(ms_aInfo)); _Analysis_assume_(ms_aModeToInfo[uMode] < ARRAYSIZE(ms_aInfo)); @@ -1104,12 +1123,12 @@ void D3DX_BC6H::Decode(bool bSigned, HDRColorA* pOut) const // Read header const size_t uHeaderBits = info.uPartitions > 0 ? 82 : 65; - while(uStartBit < uHeaderBits) + while (uStartBit < uHeaderBits) { size_t uCurBit = uStartBit; - if(GetBit(uStartBit)) + if (GetBit(uStartBit)) { - switch(desc[uCurBit].m_eField) + switch (desc[uCurBit].m_eField) { case D: uShape |= 1 << uint32_t(desc[uCurBit].m_uBit); break; case RW: aEndPts[0].A.r |= 1 << uint32_t(desc[uCurBit].m_uBit); break; @@ -1125,32 +1144,32 @@ void D3DX_BC6H::Decode(bool bSigned, HDRColorA* pOut) const case BY: aEndPts[1].A.b |= 1 << uint32_t(desc[uCurBit].m_uBit); break; case BZ: aEndPts[1].B.b |= 1 << uint32_t(desc[uCurBit].m_uBit); break; default: - { + { #ifdef _DEBUG - OutputDebugStringA( "BC6H: Invalid header bits encountered during decoding\n" ); + OutputDebugStringA("BC6H: Invalid header bits encountered during decoding\n"); #endif - FillWithErrorColors( pOut ); - return; - } + FillWithErrorColors(pOut); + return; + } } } } - assert( uShape < 64 ); - _Analysis_assume_( uShape < 64 ); + assert(uShape < 64); + _Analysis_assume_(uShape < 64); // Sign extend necessary end points - if(bSigned) + if (bSigned) { aEndPts[0].A.SignExtend(info.RGBAPrec[0][0]); } - if(bSigned || info.bTransformed) + if (bSigned || info.bTransformed) { - assert( info.uPartitions < BC6H_MAX_REGIONS ); - _Analysis_assume_( info.uPartitions < BC6H_MAX_REGIONS ); - for(size_t p = 0; p <= info.uPartitions; ++p) + assert(info.uPartitions < BC6H_MAX_REGIONS); + _Analysis_assume_(info.uPartitions < BC6H_MAX_REGIONS); + for (size_t p = 0; p <= info.uPartitions; ++p) { - if(p != 0) + if (p != 0) { aEndPts[p].A.SignExtend(info.RGBAPrec[p][0]); } @@ -1159,37 +1178,37 @@ void D3DX_BC6H::Decode(bool bSigned, HDRColorA* pOut) const } // Inverse transform the end points - if(info.bTransformed) + if (info.bTransformed) { TransformInverse(aEndPts, info.RGBAPrec[0][0], bSigned); } // Read indices - for(size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { - size_t uNumBits = IsFixUpOffset(info.uPartitions, uShape, i) ? info.uIndexPrec-1 : info.uIndexPrec; - if ( uStartBit + uNumBits > 128 ) + size_t uNumBits = IsFixUpOffset(info.uPartitions, uShape, i) ? info.uIndexPrec - 1 : info.uIndexPrec; + if (uStartBit + uNumBits > 128) { #ifdef _DEBUG - OutputDebugStringA( "BC6H: Invalid block encountered during decoding\n" ); + OutputDebugStringA("BC6H: Invalid block encountered during decoding\n"); #endif - FillWithErrorColors( pOut ); + FillWithErrorColors(pOut); return; } uint8_t uIndex = GetBits(uStartBit, uNumBits); - if ( uIndex >= ((info.uPartitions > 0) ? 8 : 16) ) + if (uIndex >= ((info.uPartitions > 0) ? 8 : 16)) { #ifdef _DEBUG - OutputDebugStringA( "BC6H: Invalid index encountered during decoding\n" ); + OutputDebugStringA("BC6H: Invalid index encountered during decoding\n"); #endif - FillWithErrorColors( pOut ); + FillWithErrorColors(pOut); return; } size_t uRegion = g_aPartitionTable[info.uPartitions][uShape][i]; - assert( uRegion < BC6H_MAX_REGIONS ); - _Analysis_assume_( uRegion < BC6H_MAX_REGIONS ); + assert(uRegion < BC6H_MAX_REGIONS); + _Analysis_assume_(uRegion < BC6H_MAX_REGIONS); // Unquantize endpoints and interpolate int r1 = Unquantize(aEndPts[uRegion].A.r, info.RGBAPrec[0][0].r, bSigned); @@ -1207,9 +1226,9 @@ void D3DX_BC6H::Decode(bool bSigned, HDRColorA* pOut) const HALF rgb[3]; fc.ToF16(rgb, bSigned); - pOut[i].r = XMConvertHalfToFloat( rgb[0] ); - pOut[i].g = XMConvertHalfToFloat( rgb[1] ); - pOut[i].b = XMConvertHalfToFloat( rgb[2] ); + pOut[i].r = XMConvertHalfToFloat(rgb[0]); + pOut[i].g = XMConvertHalfToFloat(rgb[1]); + pOut[i].b = XMConvertHalfToFloat(rgb[2]); pOut[i].a = 1.0f; } } @@ -1217,31 +1236,32 @@ void D3DX_BC6H::Decode(bool bSigned, HDRColorA* pOut) const { #ifdef _DEBUG const char* warnstr = "BC6H: Invalid mode encountered during decoding\n"; - switch( uMode ) + switch (uMode) { case 0x13: warnstr = "BC6H: Reserved mode 10011 encountered during decoding\n"; break; case 0x17: warnstr = "BC6H: Reserved mode 10111 encountered during decoding\n"; break; case 0x1B: warnstr = "BC6H: Reserved mode 11011 encountered during decoding\n"; break; case 0x1F: warnstr = "BC6H: Reserved mode 11111 encountered during decoding\n"; break; } - OutputDebugStringA( warnstr ); + OutputDebugStringA(warnstr); #endif // Per the BC6H format spec, we must return opaque black - for(size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { pOut[i] = HDRColorA(0.0f, 0.0f, 0.0f, 1.0f); } } } + _Use_decl_annotations_ void D3DX_BC6H::Encode(bool bSigned, const HDRColorA* const pIn) { - assert( pIn ); + assert(pIn); EncodeParams EP(pIn, bSigned); - for(EP.uMode = 0; EP.uMode < ARRAYSIZE(ms_aInfo) && EP.fBestErr > 0; ++EP.uMode) + for (EP.uMode = 0; EP.uMode < ARRAYSIZE(ms_aInfo) && EP.fBestErr > 0; ++EP.uMode) { const uint8_t uShapes = ms_aInfo[EP.uMode].uPartitions ? 32 : 1; // Number of rough cases to look at. reasonable values of this are 1, uShapes/4, and uShapes @@ -1251,7 +1271,7 @@ void D3DX_BC6H::Encode(bool bSigned, const HDRColorA* const pIn) uint8_t auShape[BC6H_MAX_SHAPES]; // pick the best uItems shapes and refine these. - for(EP.uShape = 0; EP.uShape < uShapes; ++EP.uShape) + for (EP.uShape = 0; EP.uShape < uShapes; ++EP.uShape) { size_t uShape = EP.uShape; afRoughMSE[uShape] = RoughMSE(&EP); @@ -1259,11 +1279,11 @@ void D3DX_BC6H::Encode(bool bSigned, const HDRColorA* const pIn) } // Bubble up the first uItems items - for(register size_t i = 0; i < uItems; i++) + for (register size_t i = 0; i < uItems; i++) { - for(register size_t j = i + 1; j < uShapes; j++) + for (register size_t j = i + 1; j < uShapes; j++) { - if(afRoughMSE[i] > afRoughMSE[j]) + if (afRoughMSE[i] > afRoughMSE[j]) { std::swap(afRoughMSE[i], afRoughMSE[j]); std::swap(auShape[i], auShape[j]); @@ -1271,7 +1291,7 @@ void D3DX_BC6H::Encode(bool bSigned, const HDRColorA* const pIn) } } - for(size_t i = 0; i < uItems && EP.fBestErr > 0; i++) + for (size_t i = 0; i < uItems && EP.fBestErr > 0; i++) { EP.uShape = auShape[i]; Refine(&EP); @@ -1286,69 +1306,71 @@ int D3DX_BC6H::Quantize(int iValue, int prec, bool bSigned) { assert(prec > 1); // didn't bother to make it work for 1 int q, s = 0; - if(bSigned) + if (bSigned) { assert(iValue >= -F16MAX && iValue <= F16MAX); - if(iValue < 0) + if (iValue < 0) { s = 1; iValue = -iValue; } - q = (prec >= 16) ? iValue : (iValue << (prec-1)) / (F16MAX+1); - if(s) + q = (prec >= 16) ? iValue : (iValue << (prec - 1)) / (F16MAX + 1); + if (s) q = -q; - assert (q > -(1 << (prec-1)) && q < (1 << (prec-1))); + assert(q > -(1 << (prec - 1)) && q < (1 << (prec - 1))); } else { assert(iValue >= 0 && iValue <= F16MAX); - q = (prec >= 15) ? iValue : (iValue << prec) / (F16MAX+1); - assert (q >= 0 && q < (1 << prec)); + q = (prec >= 15) ? iValue : (iValue << prec) / (F16MAX + 1); + assert(q >= 0 && q < (1 << prec)); } return q; } + _Use_decl_annotations_ int D3DX_BC6H::Unquantize(int comp, uint8_t uBitsPerComp, bool bSigned) { int unq = 0, s = 0; - if(bSigned) + if (bSigned) { - if(uBitsPerComp >= 16) + if (uBitsPerComp >= 16) { unq = comp; } else { - if(comp < 0) + if (comp < 0) { s = 1; comp = -comp; } - if(comp == 0) unq = 0; - else if(comp >= ((1 << (uBitsPerComp - 1)) - 1)) unq = 0x7FFF; - else unq = ((comp << 15) + 0x4000) >> (uBitsPerComp-1); + if (comp == 0) unq = 0; + else if (comp >= ((1 << (uBitsPerComp - 1)) - 1)) unq = 0x7FFF; + else unq = ((comp << 15) + 0x4000) >> (uBitsPerComp - 1); - if(s) unq = -unq; + if (s) unq = -unq; } } else { - if(uBitsPerComp >= 15) unq = comp; - else if(comp == 0) unq = 0; - else if(comp == ((1 << uBitsPerComp) - 1)) unq = 0xFFFF; + if (uBitsPerComp >= 15) unq = comp; + else if (comp == 0) unq = 0; + else if (comp == ((1 << uBitsPerComp) - 1)) unq = 0xFFFF; else unq = ((comp << 16) + 0x8000) >> uBitsPerComp; } return unq; } + _Use_decl_annotations_ int D3DX_BC6H::FinishUnquantize(int comp, bool bSigned) { - if(bSigned) + if (bSigned) { return (comp < 0) ? -(((-comp) * 31) >> 5) : (comp * 31) >> 5; // scale the magnitude by 31/32 } @@ -1363,7 +1385,7 @@ int D3DX_BC6H::FinishUnquantize(int comp, bool bSigned) _Use_decl_annotations_ bool D3DX_BC6H::EndPointsFit(const EncodeParams* pEP, const INTEndPntPair aEndPts[]) { - assert( pEP ); + assert(pEP); const bool bTransformed = ms_aInfo[pEP->uMode].bTransformed; const bool bIsSigned = pEP->bSigned; const LDRColorA& Prec0 = ms_aInfo[pEP->uMode].RGBAPrec[0][0]; @@ -1378,12 +1400,12 @@ bool D3DX_BC6H::EndPointsFit(const EncodeParams* pEP, const INTEndPntPair aEndPt aBits[1].r = NBits(aEndPts[0].B.r, bTransformed || bIsSigned); aBits[1].g = NBits(aEndPts[0].B.g, bTransformed || bIsSigned); aBits[1].b = NBits(aEndPts[0].B.b, bTransformed || bIsSigned); - if(aBits[0].r > Prec0.r || aBits[1].r > Prec1.r || - aBits[0].g > Prec0.g || aBits[1].g > Prec1.g || - aBits[0].b > Prec0.b || aBits[1].b > Prec1.b) + if (aBits[0].r > Prec0.r || aBits[1].r > Prec1.r || + aBits[0].g > Prec0.g || aBits[1].g > Prec1.g || + aBits[0].b > Prec0.b || aBits[1].b > Prec1.b) return false; - if(ms_aInfo[pEP->uMode].uPartitions) + if (ms_aInfo[pEP->uMode].uPartitions) { aBits[2].r = NBits(aEndPts[1].A.r, bTransformed || bIsSigned); aBits[2].g = NBits(aEndPts[1].A.g, bTransformed || bIsSigned); @@ -1392,46 +1414,47 @@ bool D3DX_BC6H::EndPointsFit(const EncodeParams* pEP, const INTEndPntPair aEndPt aBits[3].g = NBits(aEndPts[1].B.g, bTransformed || bIsSigned); aBits[3].b = NBits(aEndPts[1].B.b, bTransformed || bIsSigned); - if(aBits[2].r > Prec2.r || aBits[3].r > Prec3.r || - aBits[2].g > Prec2.g || aBits[3].g > Prec3.g || - aBits[2].b > Prec2.b || aBits[3].b > Prec3.b) + if (aBits[2].r > Prec2.r || aBits[3].r > Prec3.r || + aBits[2].g > Prec2.g || aBits[3].g > Prec3.g || + aBits[2].b > Prec2.b || aBits[3].b > Prec3.b) return false; } return true; } + _Use_decl_annotations_ void D3DX_BC6H::GeneratePaletteQuantized(const EncodeParams* pEP, const INTEndPntPair& endPts, INTColor aPalette[]) const { - assert( pEP ); + assert(pEP); const size_t uIndexPrec = ms_aInfo[pEP->uMode].uIndexPrec; const size_t uNumIndices = size_t(1) << uIndexPrec; - assert( uNumIndices > 0 ); - _Analysis_assume_( uNumIndices > 0 ); + assert(uNumIndices > 0); + _Analysis_assume_(uNumIndices > 0); const LDRColorA& Prec = ms_aInfo[pEP->uMode].RGBAPrec[0][0]; // scale endpoints INTEndPntPair unqEndPts; - unqEndPts.A.r = Unquantize(endPts.A.r, Prec.r, pEP->bSigned); - unqEndPts.A.g = Unquantize(endPts.A.g, Prec.g, pEP->bSigned); - unqEndPts.A.b = Unquantize(endPts.A.b, Prec.b, pEP->bSigned); + unqEndPts.A.r = Unquantize(endPts.A.r, Prec.r, pEP->bSigned); + unqEndPts.A.g = Unquantize(endPts.A.g, Prec.g, pEP->bSigned); + unqEndPts.A.b = Unquantize(endPts.A.b, Prec.b, pEP->bSigned); unqEndPts.B.r = Unquantize(endPts.B.r, Prec.r, pEP->bSigned); unqEndPts.B.g = Unquantize(endPts.B.g, Prec.g, pEP->bSigned); unqEndPts.B.b = Unquantize(endPts.B.b, Prec.b, pEP->bSigned); // interpolate const int* aWeights = nullptr; - switch(uIndexPrec) + switch (uIndexPrec) { case 3: aWeights = g_aWeights3; assert(uNumIndices <= 8); _Analysis_assume_(uNumIndices <= 8); break; case 4: aWeights = g_aWeights4; assert(uNumIndices <= 16); _Analysis_assume_(uNumIndices <= 16); break; default: assert(false); - for(size_t i = 0; i < uNumIndices; ++i) + for (size_t i = 0; i < uNumIndices; ++i) { - #pragma prefast(suppress:22102 22103, "writing blocks in two halves confuses tool") - aPalette[i] = INTColor(0,0,0); +#pragma prefast(suppress:22102 22103, "writing blocks in two halves confuses tool") + aPalette[i] = INTColor(0, 0, 0); } return; } @@ -1450,11 +1473,12 @@ void D3DX_BC6H::GeneratePaletteQuantized(const EncodeParams* pEP, const INTEndPn } } + // given a collection of colors and quantized endpoints, generate a palette, choose best entries, and return a single toterr _Use_decl_annotations_ float D3DX_BC6H::MapColorsQuantized(const EncodeParams* pEP, const INTColor aColors[], size_t np, const INTEndPntPair &endPts) const { - assert( pEP ); + assert(pEP); const uint8_t uIndexPrec = ms_aInfo[pEP->uMode].uIndexPrec; const uint8_t uNumIndices = 1 << uIndexPrec; @@ -1462,36 +1486,37 @@ float D3DX_BC6H::MapColorsQuantized(const EncodeParams* pEP, const INTColor aCol GeneratePaletteQuantized(pEP, endPts, aPalette); float fTotErr = 0; - for(size_t i = 0; i < np; ++i) + for (size_t i = 0; i < np; ++i) { - XMVECTOR vcolors = XMLoadSInt4( reinterpret_cast( &aColors[i] ) ); + XMVECTOR vcolors = XMLoadSInt4(reinterpret_cast(&aColors[i])); // Compute ErrorMetricRGB - XMVECTOR tpal = XMLoadSInt4( reinterpret_cast( &aPalette[0] ) ); - tpal = XMVectorSubtract( vcolors, tpal ); - float fBestErr = XMVectorGetX( XMVector3Dot( tpal, tpal ) ); + XMVECTOR tpal = XMLoadSInt4(reinterpret_cast(&aPalette[0])); + tpal = XMVectorSubtract(vcolors, tpal); + float fBestErr = XMVectorGetX(XMVector3Dot(tpal, tpal)); - for(int j = 1; j < uNumIndices && fBestErr > 0; ++j) + for (int j = 1; j < uNumIndices && fBestErr > 0; ++j) { // Compute ErrorMetricRGB - tpal = XMLoadSInt4( reinterpret_cast( &aPalette[j] ) ); - tpal = XMVectorSubtract( vcolors, tpal ); - float fErr = XMVectorGetX( XMVector3Dot( tpal, tpal ) ); - if(fErr > fBestErr) break; // error increased, so we're done searching - if(fErr < fBestErr) fBestErr = fErr; + tpal = XMLoadSInt4(reinterpret_cast(&aPalette[j])); + tpal = XMVectorSubtract(vcolors, tpal); + float fErr = XMVectorGetX(XMVector3Dot(tpal, tpal)); + if (fErr > fBestErr) break; // error increased, so we're done searching + if (fErr < fBestErr) fBestErr = fErr; } fTotErr += fBestErr; } return fTotErr; } + _Use_decl_annotations_ float D3DX_BC6H::PerturbOne(const EncodeParams* pEP, const INTColor aColors[], size_t np, uint8_t ch, - const INTEndPntPair& oldEndPts, INTEndPntPair& newEndPts, float fOldErr, int do_b) const + const INTEndPntPair& oldEndPts, INTEndPntPair& newEndPts, float fOldErr, int do_b) const { - assert( pEP ); + assert(pEP); uint8_t uPrec; - switch(ch) + switch (ch) { case 0: uPrec = ms_aInfo[pEP->uMode].RGBAPrec[0][0].r; break; case 1: uPrec = ms_aInfo[pEP->uMode].RGBAPrec[0][0].g; break; @@ -1506,27 +1531,27 @@ float D3DX_BC6H::PerturbOne(const EncodeParams* pEP, const INTColor aColors[], s tmpEndPts = newEndPts = oldEndPts; // do a logarithmic search for the best error for this endpoint (which) - for(int step = 1 << (uPrec-1); step; step >>= 1) + for (int step = 1 << (uPrec - 1); step; step >>= 1) { bool bImproved = false; - for(int sign = -1; sign <= 1; sign += 2) + for (int sign = -1; sign <= 1; sign += 2) { - if(do_b == 0) + if (do_b == 0) { tmpEndPts.A[ch] = newEndPts.A[ch] + sign * step; - if(tmpEndPts.A[ch] < 0 || tmpEndPts.A[ch] >= (1 << uPrec)) + if (tmpEndPts.A[ch] < 0 || tmpEndPts.A[ch] >= (1 << uPrec)) continue; } else { tmpEndPts.B[ch] = newEndPts.B[ch] + sign * step; - if(tmpEndPts.B[ch] < 0 || tmpEndPts.B[ch] >= (1 << uPrec)) + if (tmpEndPts.B[ch] < 0 || tmpEndPts.B[ch] >= (1 << uPrec)) continue; } float fErr = MapColorsQuantized(pEP, aColors, np, tmpEndPts); - if(fErr < fMinErr) + if (fErr < fMinErr) { bImproved = true; fMinErr = fErr; @@ -1534,9 +1559,9 @@ float D3DX_BC6H::PerturbOne(const EncodeParams* pEP, const INTColor aColors[], s } } // if this was an improvement, move the endpoint and continue search from there - if(bImproved) + if (bImproved) { - if(do_b == 0) + if (do_b == 0) newEndPts.A[ch] += beststep; else newEndPts.B[ch] += beststep; @@ -1545,11 +1570,12 @@ float D3DX_BC6H::PerturbOne(const EncodeParams* pEP, const INTColor aColors[], s return fMinErr; } + _Use_decl_annotations_ void D3DX_BC6H::OptimizeOne(const EncodeParams* pEP, const INTColor aColors[], size_t np, float aOrgErr, - const INTEndPntPair &aOrgEndPts, INTEndPntPair &aOptEndPts) const + const INTEndPntPair &aOrgEndPts, INTEndPntPair &aOptEndPts) const { - assert( pEP ); + assert(pEP); float aOptErr = aOrgErr; aOptEndPts.A = aOrgEndPts.A; aOptEndPts.B = aOrgEndPts.B; @@ -1559,35 +1585,35 @@ void D3DX_BC6H::OptimizeOne(const EncodeParams* pEP, const INTColor aColors[], s int do_b; // now optimize each channel separately - for(uint8_t ch = 0; ch < 3; ++ch) + for (uint8_t ch = 0; ch < 3; ++ch) { // figure out which endpoint when perturbed gives the most improvement and start there // if we just alternate, we can easily end up in a local minima float fErr0 = PerturbOne(pEP, aColors, np, ch, aOptEndPts, new_a, aOptErr, 0); // perturb endpt A float fErr1 = PerturbOne(pEP, aColors, np, ch, aOptEndPts, new_b, aOptErr, 1); // perturb endpt B - if(fErr0 < fErr1) + if (fErr0 < fErr1) { - if(fErr0 >= aOptErr) continue; + if (fErr0 >= aOptErr) continue; aOptEndPts.A[ch] = new_a.A[ch]; aOptErr = fErr0; do_b = 1; // do B next } else { - if(fErr1 >= aOptErr) continue; + if (fErr1 >= aOptErr) continue; aOptEndPts.B[ch] = new_b.B[ch]; aOptErr = fErr1; do_b = 0; // do A next } // now alternate endpoints and keep trying until there is no improvement - for(;;) + for (;;) { float fErr = PerturbOne(pEP, aColors, np, ch, aOptEndPts, newEndPts, aOptErr, do_b); - if(fErr >= aOptErr) + if (fErr >= aOptErr) break; - if(do_b == 0) + if (do_b == 0) aOptEndPts.A[ch] = newEndPts.A[ch]; else aOptEndPts.B[ch] = newEndPts.B[ch]; @@ -1597,22 +1623,23 @@ void D3DX_BC6H::OptimizeOne(const EncodeParams* pEP, const INTColor aColors[], s } } + _Use_decl_annotations_ void D3DX_BC6H::OptimizeEndPoints(const EncodeParams* pEP, const float aOrgErr[], const INTEndPntPair aOrgEndPts[], INTEndPntPair aOptEndPts[]) const { - assert( pEP ); + assert(pEP); const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions; - assert( uPartitions < BC6H_MAX_REGIONS ); - _Analysis_assume_( uPartitions < BC6H_MAX_REGIONS ); + assert(uPartitions < BC6H_MAX_REGIONS); + _Analysis_assume_(uPartitions < BC6H_MAX_REGIONS); INTColor aPixels[NUM_PIXELS_PER_BLOCK]; - - for(size_t p = 0; p <= uPartitions; ++p) + + for (size_t p = 0; p <= uPartitions; ++p) { // collect the pixels in the region size_t np = 0; - for(size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { - if(g_aPartitionTable[p][pEP->uShape][i] == p) + if (g_aPartitionTable[p][pEP->uShape][i] == p) { aPixels[np++] = pEP->aIPixels[i]; } @@ -1622,67 +1649,69 @@ void D3DX_BC6H::OptimizeEndPoints(const EncodeParams* pEP, const float aOrgErr[] } } + // Swap endpoints as needed to ensure that the indices at fix up have a 0 high-order bit _Use_decl_annotations_ void D3DX_BC6H::SwapIndices(const EncodeParams* pEP, INTEndPntPair aEndPts[], size_t aIndices[]) { - assert( pEP ); + assert(pEP); const size_t uPartitions = ms_aInfo[pEP->uMode].uPartitions; const size_t uNumIndices = size_t(1) << ms_aInfo[pEP->uMode].uIndexPrec; const size_t uHighIndexBit = uNumIndices >> 1; - assert( uPartitions < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES ); - _Analysis_assume_( uPartitions < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES ); + assert(uPartitions < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES); + _Analysis_assume_(uPartitions < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES); - for(size_t p = 0; p <= uPartitions; ++p) + for (size_t p = 0; p <= uPartitions; ++p) { size_t i = g_aFixUp[uPartitions][pEP->uShape][p]; assert(g_aPartitionTable[uPartitions][pEP->uShape][i] == p); - if(aIndices[i] & uHighIndexBit) + if (aIndices[i] & uHighIndexBit) { // high bit is set, swap the aEndPts and indices for this region std::swap(aEndPts[p].A, aEndPts[p].B); - for(size_t j = 0; j < NUM_PIXELS_PER_BLOCK; ++j) - if(g_aPartitionTable[uPartitions][pEP->uShape][j] == p) + for (size_t j = 0; j < NUM_PIXELS_PER_BLOCK; ++j) + if (g_aPartitionTable[uPartitions][pEP->uShape][j] == p) aIndices[j] = uNumIndices - 1 - aIndices[j]; } } } + // assign indices given a tile, shape, and quantized endpoints, return toterr for each region _Use_decl_annotations_ void D3DX_BC6H::AssignIndices(const EncodeParams* pEP, const INTEndPntPair aEndPts[], size_t aIndices[], float aTotErr[]) const { - assert( pEP ); + assert(pEP); const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions; const uint8_t uNumIndices = 1 << ms_aInfo[pEP->uMode].uIndexPrec; - assert( uPartitions < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES ); - _Analysis_assume_( uPartitions < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES ); + assert(uPartitions < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES); + _Analysis_assume_(uPartitions < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES); // build list of possibles INTColor aPalette[BC6H_MAX_REGIONS][BC6H_MAX_INDICES]; - for(size_t p = 0; p <= uPartitions; ++p) + for (size_t p = 0; p <= uPartitions; ++p) { GeneratePaletteQuantized(pEP, aEndPts[p], aPalette[p]); aTotErr[p] = 0; } - for(size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { const uint8_t uRegion = g_aPartitionTable[uPartitions][pEP->uShape][i]; - assert( uRegion < BC6H_MAX_REGIONS ); - _Analysis_assume_( uRegion < BC6H_MAX_REGIONS ); + assert(uRegion < BC6H_MAX_REGIONS); + _Analysis_assume_(uRegion < BC6H_MAX_REGIONS); float fBestErr = Norm(pEP->aIPixels[i], aPalette[uRegion][0]); aIndices[i] = 0; - for(uint8_t j = 1; j < uNumIndices && fBestErr > 0; ++j) + for (uint8_t j = 1; j < uNumIndices && fBestErr > 0; ++j) { float fErr = Norm(pEP->aIPixels[i], aPalette[uRegion][j]); - if(fErr > fBestErr) break; // error increased, so we're done searching - if(fErr < fBestErr) + if (fErr > fBestErr) break; // error increased, so we're done searching + if (fErr < fBestErr) { fBestErr = fErr; aIndices[i] = j; @@ -1692,17 +1721,18 @@ void D3DX_BC6H::AssignIndices(const EncodeParams* pEP, const INTEndPntPair aEndP } } + _Use_decl_annotations_ void D3DX_BC6H::QuantizeEndPts(const EncodeParams* pEP, INTEndPntPair* aQntEndPts) const { - assert( pEP && aQntEndPts ); + assert(pEP && aQntEndPts); const INTEndPntPair* aUnqEndPts = pEP->aUnqEndPts[pEP->uShape]; const LDRColorA& Prec = ms_aInfo[pEP->uMode].RGBAPrec[0][0]; const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions; - assert( uPartitions < BC6H_MAX_REGIONS ); - _Analysis_assume_( uPartitions < BC6H_MAX_REGIONS ); + assert(uPartitions < BC6H_MAX_REGIONS); + _Analysis_assume_(uPartitions < BC6H_MAX_REGIONS); - for(size_t p = 0; p <= uPartitions; ++p) + for (size_t p = 0; p <= uPartitions; ++p) { aQntEndPts[p].A.r = Quantize(aUnqEndPts[p].A.r, Prec.r, pEP->bSigned); aQntEndPts[p].A.g = Quantize(aUnqEndPts[p].A.g, Prec.g, pEP->bSigned); @@ -1713,10 +1743,11 @@ void D3DX_BC6H::QuantizeEndPts(const EncodeParams* pEP, INTEndPntPair* aQntEndPt } } + _Use_decl_annotations_ void D3DX_BC6H::EmitBlock(const EncodeParams* pEP, const INTEndPntPair aEndPts[], const size_t aIndices[]) { - assert( pEP ); + assert(pEP); const uint8_t uRealMode = ms_aInfo[pEP->uMode].uMode; const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions; const uint8_t uIndexPrec = ms_aInfo[pEP->uMode].uIndexPrec; @@ -1724,9 +1755,9 @@ void D3DX_BC6H::EmitBlock(const EncodeParams* pEP, const INTEndPntPair aEndPts[] const ModeDescriptor* desc = ms_aDesc[pEP->uMode]; size_t uStartBit = 0; - while(uStartBit < uHeaderBits) + while (uStartBit < uHeaderBits) { - switch(desc[uStartBit].m_eField) + switch (desc[uStartBit].m_eField) { case M: SetBit(uStartBit, uint8_t(uRealMode >> desc[uStartBit].m_uBit) & 0x01); break; case D: SetBit(uStartBit, uint8_t(pEP->uShape >> desc[uStartBit].m_uBit) & 0x01); break; @@ -1746,23 +1777,24 @@ void D3DX_BC6H::EmitBlock(const EncodeParams* pEP, const INTEndPntPair aEndPts[] } } - for(size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { - if(IsFixUpOffset(ms_aInfo[pEP->uMode].uPartitions, pEP->uShape, i)) - SetBits(uStartBit, uIndexPrec - 1, static_cast( aIndices[i] )); + if (IsFixUpOffset(ms_aInfo[pEP->uMode].uPartitions, pEP->uShape, i)) + SetBits(uStartBit, uIndexPrec - 1, static_cast(aIndices[i])); else - SetBits(uStartBit, uIndexPrec, static_cast( aIndices[i] )); + SetBits(uStartBit, uIndexPrec, static_cast(aIndices[i])); } assert(uStartBit == 128); } + _Use_decl_annotations_ void D3DX_BC6H::Refine(EncodeParams* pEP) { - assert( pEP ); + assert(pEP); const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions; - assert( uPartitions < BC6H_MAX_REGIONS ); - _Analysis_assume_( uPartitions < BC6H_MAX_REGIONS ); + assert(uPartitions < BC6H_MAX_REGIONS); + _Analysis_assume_(uPartitions < BC6H_MAX_REGIONS); const bool bTransformed = ms_aInfo[pEP->uMode].bTransformed; float aOrgErr[BC6H_MAX_REGIONS], aOptErr[BC6H_MAX_REGIONS]; @@ -1773,44 +1805,45 @@ void D3DX_BC6H::Refine(EncodeParams* pEP) AssignIndices(pEP, aOrgEndPts, aOrgIdx, aOrgErr); SwapIndices(pEP, aOrgEndPts, aOrgIdx); - if(bTransformed) TransformForward(aOrgEndPts); - if(EndPointsFit(pEP, aOrgEndPts)) + if (bTransformed) TransformForward(aOrgEndPts); + if (EndPointsFit(pEP, aOrgEndPts)) { - if(bTransformed) TransformInverse(aOrgEndPts, ms_aInfo[pEP->uMode].RGBAPrec[0][0], pEP->bSigned); + if (bTransformed) TransformInverse(aOrgEndPts, ms_aInfo[pEP->uMode].RGBAPrec[0][0], pEP->bSigned); OptimizeEndPoints(pEP, aOrgErr, aOrgEndPts, aOptEndPts); AssignIndices(pEP, aOptEndPts, aOptIdx, aOptErr); SwapIndices(pEP, aOptEndPts, aOptIdx); float fOrgTotErr = 0.0f, fOptTotErr = 0.0f; - for(size_t p = 0; p <= uPartitions; ++p) + for (size_t p = 0; p <= uPartitions; ++p) { fOrgTotErr += aOrgErr[p]; fOptTotErr += aOptErr[p]; } - if(bTransformed) TransformForward(aOptEndPts); - if(EndPointsFit(pEP, aOptEndPts) && fOptTotErr < fOrgTotErr && fOptTotErr < pEP->fBestErr) + if (bTransformed) TransformForward(aOptEndPts); + if (EndPointsFit(pEP, aOptEndPts) && fOptTotErr < fOrgTotErr && fOptTotErr < pEP->fBestErr) { pEP->fBestErr = fOptTotErr; EmitBlock(pEP, aOptEndPts, aOptIdx); } - else if(fOrgTotErr < pEP->fBestErr) + else if (fOrgTotErr < pEP->fBestErr) { // either it stopped fitting when we optimized it, or there was no improvement // so go back to the unoptimized endpoints which we know will fit - if(bTransformed) TransformForward(aOrgEndPts); + if (bTransformed) TransformForward(aOrgEndPts); pEP->fBestErr = fOrgTotErr; EmitBlock(pEP, aOrgEndPts, aOrgIdx); } } } + _Use_decl_annotations_ void D3DX_BC6H::GeneratePaletteUnquantized(const EncodeParams* pEP, size_t uRegion, INTColor aPalette[]) { - assert( pEP ); - assert( uRegion < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES ); - _Analysis_assume_( uRegion < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES ); + assert(pEP); + assert(uRegion < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES); + _Analysis_assume_(uRegion < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES); const INTEndPntPair& endPts = pEP->aUnqEndPts[pEP->uShape][uRegion]; const uint8_t uIndexPrec = ms_aInfo[pEP->uMode].uIndexPrec; const uint8_t uNumIndices = 1 << uIndexPrec; @@ -1818,21 +1851,21 @@ void D3DX_BC6H::GeneratePaletteUnquantized(const EncodeParams* pEP, size_t uRegi _Analysis_assume_(uNumIndices > 0); const int* aWeights = nullptr; - switch(uIndexPrec) + switch (uIndexPrec) { case 3: aWeights = g_aWeights3; assert(uNumIndices <= 8); _Analysis_assume_(uNumIndices <= 8); break; case 4: aWeights = g_aWeights4; assert(uNumIndices <= 16); _Analysis_assume_(uNumIndices <= 16); break; default: assert(false); - for(size_t i = 0; i < uNumIndices; ++i) + for (size_t i = 0; i < uNumIndices; ++i) { - #pragma prefast(suppress:22102 22103, "writing blocks in two halves confuses tool") - aPalette[i] = INTColor(0,0,0); +#pragma prefast(suppress:22102 22103, "writing blocks in two halves confuses tool") + aPalette[i] = INTColor(0, 0, 0); } return; } - for(register size_t i = 0; i < uNumIndices; ++i) + for (register size_t i = 0; i < uNumIndices; ++i) { aPalette[i].r = (endPts.A.r * (BC67_WEIGHT_MAX - aWeights[i]) + endPts.B.r * aWeights[i] + BC67_WEIGHT_ROUND) >> BC67_WEIGHT_SHIFT; aPalette[i].g = (endPts.A.g * (BC67_WEIGHT_MAX - aWeights[i]) + endPts.B.g * aWeights[i] + BC67_WEIGHT_ROUND) >> BC67_WEIGHT_SHIFT; @@ -1840,24 +1873,25 @@ void D3DX_BC6H::GeneratePaletteUnquantized(const EncodeParams* pEP, size_t uRegi } } + _Use_decl_annotations_ float D3DX_BC6H::MapColors(const EncodeParams* pEP, size_t uRegion, size_t np, const size_t* auIndex) const { - assert( pEP ); + assert(pEP); const uint8_t uIndexPrec = ms_aInfo[pEP->uMode].uIndexPrec; const uint8_t uNumIndices = 1 << uIndexPrec; INTColor aPalette[BC6H_MAX_INDICES]; GeneratePaletteUnquantized(pEP, uRegion, aPalette); float fTotalErr = 0.0f; - for(size_t i = 0; i < np; ++i) + for (size_t i = 0; i < np; ++i) { float fBestErr = Norm(pEP->aIPixels[auIndex[i]], aPalette[0]); - for(uint8_t j = 1; j < uNumIndices && fBestErr > 0.0f; ++j) + for (uint8_t j = 1; j < uNumIndices && fBestErr > 0.0f; ++j) { float fErr = Norm(pEP->aIPixels[auIndex[i]], aPalette[j]); - if(fErr > fBestErr) break; // error increased, so we're done searching - if(fErr < fBestErr) fBestErr = fErr; + if (fErr > fBestErr) break; // error increased, so we're done searching + if (fErr < fBestErr) fBestErr = fErr; } fTotalErr += fBestErr; } @@ -1868,25 +1902,25 @@ float D3DX_BC6H::MapColors(const EncodeParams* pEP, size_t uRegion, size_t np, c _Use_decl_annotations_ float D3DX_BC6H::RoughMSE(EncodeParams* pEP) const { - assert( pEP ); - assert( pEP->uShape < BC6H_MAX_SHAPES); - _Analysis_assume_( pEP->uShape < BC6H_MAX_SHAPES); + assert(pEP); + assert(pEP->uShape < BC6H_MAX_SHAPES); + _Analysis_assume_(pEP->uShape < BC6H_MAX_SHAPES); INTEndPntPair* aEndPts = pEP->aUnqEndPts[pEP->uShape]; const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions; - assert( uPartitions < BC6H_MAX_REGIONS ); - _Analysis_assume_( uPartitions < BC6H_MAX_REGIONS ); + assert(uPartitions < BC6H_MAX_REGIONS); + _Analysis_assume_(uPartitions < BC6H_MAX_REGIONS); size_t auPixIdx[NUM_PIXELS_PER_BLOCK]; float fError = 0.0f; - for(size_t p = 0; p <= uPartitions; ++p) + for (size_t p = 0; p <= uPartitions; ++p) { size_t np = 0; - for(register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + for (register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { - if(g_aPartitionTable[uPartitions][pEP->uShape][i] == p) + if (g_aPartitionTable[uPartitions][pEP->uShape][i] == p) { auPixIdx[np++] = i; } @@ -1894,13 +1928,13 @@ float D3DX_BC6H::RoughMSE(EncodeParams* pEP) const // handle simple cases assert(np > 0); - if(np == 1) + if (np == 1) { aEndPts[p].A = pEP->aIPixels[auPixIdx[0]]; aEndPts[p].B = pEP->aIPixels[auPixIdx[0]]; continue; } - else if(np == 2) + else if (np == 2) { aEndPts[p].A = pEP->aIPixels[auPixIdx[0]]; aEndPts[p].B = pEP->aIPixels[auPixIdx[1]]; @@ -1911,7 +1945,7 @@ float D3DX_BC6H::RoughMSE(EncodeParams* pEP) const OptimizeRGB(pEP->aHDRPixels, &epA, &epB, 4, np, auPixIdx); aEndPts[p].A.Set(epA, pEP->bSigned); aEndPts[p].B.Set(epB, pEP->bSigned); - if(pEP->bSigned) + if (pEP->bSigned) { aEndPts[p].A.Clamp(-F16MAX, F16MAX); aEndPts[p].B.Clamp(-F16MAX, F16MAX); @@ -1929,24 +1963,23 @@ float D3DX_BC6H::RoughMSE(EncodeParams* pEP) const } - //------------------------------------------------------------------------------------- // BC7 Compression //------------------------------------------------------------------------------------- _Use_decl_annotations_ void D3DX_BC7::Decode(HDRColorA* pOut) const { - assert( pOut ); + assert(pOut); size_t uFirst = 0; - while(uFirst < 128 && !GetBit(uFirst)) {} + while (uFirst < 128 && !GetBit(uFirst)) {} uint8_t uMode = uint8_t(uFirst - 1); - if(uMode < 8) + if (uMode < 8) { const uint8_t uPartitions = ms_aInfo[uMode].uPartitions; - assert( uPartitions < BC7_MAX_REGIONS ); - _Analysis_assume_( uPartitions < BC7_MAX_REGIONS ); + assert(uPartitions < BC7_MAX_REGIONS); + _Analysis_assume_(uPartitions < BC7_MAX_REGIONS); const uint8_t uNumEndPts = (uPartitions + 1) << 1; const uint8_t uIndexPrec = ms_aInfo[uMode].uIndexPrec; @@ -1955,30 +1988,30 @@ void D3DX_BC7::Decode(HDRColorA* pOut) const size_t uStartBit = uMode + 1; uint8_t P[6]; uint8_t uShape = GetBits(uStartBit, ms_aInfo[uMode].uPartitionBits); - assert( uShape < BC7_MAX_SHAPES ); - _Analysis_assume_( uShape < BC7_MAX_SHAPES ); + assert(uShape < BC7_MAX_SHAPES); + _Analysis_assume_(uShape < BC7_MAX_SHAPES); uint8_t uRotation = GetBits(uStartBit, ms_aInfo[uMode].uRotationBits); - assert( uRotation < 4 ); + assert(uRotation < 4); uint8_t uIndexMode = GetBits(uStartBit, ms_aInfo[uMode].uIndexModeBits); - assert( uIndexMode < 2 ); + assert(uIndexMode < 2); LDRColorA c[BC7_MAX_REGIONS << 1]; const LDRColorA RGBAPrec = ms_aInfo[uMode].RGBAPrec; const LDRColorA RGBAPrecWithP = ms_aInfo[uMode].RGBAPrecWithP; - assert( uNumEndPts <= (BC7_MAX_REGIONS << 1) ); + assert(uNumEndPts <= (BC7_MAX_REGIONS << 1)); // Red channel - for(i = 0; i < uNumEndPts; i++) + for (i = 0; i < uNumEndPts; i++) { - if ( uStartBit + RGBAPrec.r > 128 ) + if (uStartBit + RGBAPrec.r > 128) { #ifdef _DEBUG - OutputDebugStringA( "BC7: Invalid block encountered during decoding\n" ); + OutputDebugStringA("BC7: Invalid block encountered during decoding\n"); #endif - FillWithErrorColors( pOut ); + FillWithErrorColors(pOut); return; } @@ -1986,29 +2019,29 @@ void D3DX_BC7::Decode(HDRColorA* pOut) const } // Green channel - for(i = 0; i < uNumEndPts; i++) + for (i = 0; i < uNumEndPts; i++) { - if ( uStartBit + RGBAPrec.g > 128 ) + if (uStartBit + RGBAPrec.g > 128) { #ifdef _DEBUG - OutputDebugStringA( "BC7: Invalid block encountered during decoding\n" ); + OutputDebugStringA("BC7: Invalid block encountered during decoding\n"); #endif - FillWithErrorColors( pOut ); + FillWithErrorColors(pOut); return; } - c[i].g = GetBits(uStartBit, RGBAPrec.g); + c[i].g = GetBits(uStartBit, RGBAPrec.g); } // Blue channel - for(i = 0; i < uNumEndPts; i++) + for (i = 0; i < uNumEndPts; i++) { - if ( uStartBit + RGBAPrec.b > 128 ) + if (uStartBit + RGBAPrec.b > 128) { #ifdef _DEBUG - OutputDebugStringA( "BC7: Invalid block encountered during decoding\n" ); + OutputDebugStringA("BC7: Invalid block encountered during decoding\n"); #endif - FillWithErrorColors( pOut ); + FillWithErrorColors(pOut); return; } @@ -2016,14 +2049,14 @@ void D3DX_BC7::Decode(HDRColorA* pOut) const } // Alpha channel - for(i = 0; i < uNumEndPts; i++) + for (i = 0; i < uNumEndPts; i++) { - if ( uStartBit + RGBAPrec.a > 128 ) + if (uStartBit + RGBAPrec.a > 128) { #ifdef _DEBUG - OutputDebugStringA( "BC7: Invalid block encountered during decoding\n" ); + OutputDebugStringA("BC7: Invalid block encountered during decoding\n"); #endif - FillWithErrorColors( pOut ); + FillWithErrorColors(pOut); return; } @@ -2031,30 +2064,30 @@ void D3DX_BC7::Decode(HDRColorA* pOut) const } // P-bits - assert( ms_aInfo[uMode].uPBits <= 6 ); - _Analysis_assume_( ms_aInfo[uMode].uPBits <= 6 ); - for(i = 0; i < ms_aInfo[uMode].uPBits; i++) + assert(ms_aInfo[uMode].uPBits <= 6); + _Analysis_assume_(ms_aInfo[uMode].uPBits <= 6); + for (i = 0; i < ms_aInfo[uMode].uPBits; i++) { - if ( uStartBit > 127 ) + if (uStartBit > 127) { #ifdef _DEBUG - OutputDebugStringA( "BC7: Invalid block encountered during decoding\n" ); + OutputDebugStringA("BC7: Invalid block encountered during decoding\n"); #endif - FillWithErrorColors( pOut ); + FillWithErrorColors(pOut); return; } P[i] = GetBit(uStartBit); } - if(ms_aInfo[uMode].uPBits) + if (ms_aInfo[uMode].uPBits) { - for(i = 0; i < uNumEndPts; i++) + for (i = 0; i < uNumEndPts; i++) { size_t pi = i * ms_aInfo[uMode].uPBits / uNumEndPts; - for(register uint8_t ch = 0; ch < BC7_NUM_CHANNELS; ch++) + for (register uint8_t ch = 0; ch < BC7_NUM_CHANNELS; ch++) { - if(RGBAPrec[ch] != RGBAPrecWithP[ch]) + if (RGBAPrec[ch] != RGBAPrecWithP[ch]) { c[i][ch] = (c[i][ch] << 1) | P[pi]; } @@ -2062,7 +2095,7 @@ void D3DX_BC7::Decode(HDRColorA* pOut) const } } - for(i = 0; i < uNumEndPts; i++) + for (i = 0; i < uNumEndPts; i++) { c[i] = Unquantize(c[i], RGBAPrecWithP); } @@ -2070,49 +2103,49 @@ void D3DX_BC7::Decode(HDRColorA* pOut) const uint8_t w1[NUM_PIXELS_PER_BLOCK], w2[NUM_PIXELS_PER_BLOCK]; // read color indices - for(i = 0; i < NUM_PIXELS_PER_BLOCK; i++) + for (i = 0; i < NUM_PIXELS_PER_BLOCK; i++) { size_t uNumBits = IsFixUpOffset(ms_aInfo[uMode].uPartitions, uShape, i) ? uIndexPrec - 1 : uIndexPrec; - if ( uStartBit + uNumBits > 128 ) + if (uStartBit + uNumBits > 128) { #ifdef _DEBUG - OutputDebugStringA( "BC7: Invalid block encountered during decoding\n" ); + OutputDebugStringA("BC7: Invalid block encountered during decoding\n"); #endif - FillWithErrorColors( pOut ); + FillWithErrorColors(pOut); return; } w1[i] = GetBits(uStartBit, uNumBits); } // read alpha indices - if(uIndexPrec2) + if (uIndexPrec2) { - for(i = 0; i < NUM_PIXELS_PER_BLOCK; i++) + for (i = 0; i < NUM_PIXELS_PER_BLOCK; i++) { size_t uNumBits = i ? uIndexPrec2 : uIndexPrec2 - 1; - if ( uStartBit + uNumBits > 128 ) + if (uStartBit + uNumBits > 128) { #ifdef _DEBUG - OutputDebugStringA( "BC7: Invalid block encountered during decoding\n" ); + OutputDebugStringA("BC7: Invalid block encountered during decoding\n"); #endif - FillWithErrorColors( pOut ); + FillWithErrorColors(pOut); return; } - w2[i] = GetBits(uStartBit, uNumBits ); + w2[i] = GetBits(uStartBit, uNumBits); } } - for(i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + for (i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { uint8_t uRegion = g_aPartitionTable[uPartitions][uShape][i]; LDRColorA outPixel; - if(uIndexPrec2 == 0) + if (uIndexPrec2 == 0) { LDRColorA::Interpolate(c[uRegion << 1], c[(uRegion << 1) + 1], w1[i], w1[i], uIndexPrec, uIndexPrec, outPixel); } else { - if(uIndexMode == 0) + if (uIndexMode == 0) { LDRColorA::Interpolate(c[uRegion << 1], c[(uRegion << 1) + 1], w1[i], w2[i], uIndexPrec, uIndexPrec2, outPixel); } @@ -2122,7 +2155,7 @@ void D3DX_BC7::Decode(HDRColorA* pOut) const } } - switch(uRotation) + switch (uRotation) { case 1: std::swap(outPixel.r, outPixel.a); break; case 2: std::swap(outPixel.g, outPixel.a); break; @@ -2135,41 +2168,41 @@ void D3DX_BC7::Decode(HDRColorA* pOut) const else { #ifdef _DEBUG - OutputDebugStringA( "BC7: Reserved mode 8 encountered during decoding\n" ); + OutputDebugStringA("BC7: Reserved mode 8 encountered during decoding\n"); #endif // Per the BC7 format spec, we must return transparent black - memset( pOut, 0, sizeof(HDRColorA) * NUM_PIXELS_PER_BLOCK ); + memset(pOut, 0, sizeof(HDRColorA) * NUM_PIXELS_PER_BLOCK); } } _Use_decl_annotations_ void D3DX_BC7::Encode(bool skip3subsets, const HDRColorA* const pIn) { - assert( pIn ); + assert(pIn); D3DX_BC7 final = *this; EncodeParams EP(pIn); float fMSEBest = FLT_MAX; - - for(size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + + for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { - EP.aLDRPixels[i].r = uint8_t( std::max( 0.0f, std::min( 255.0f, pIn[i].r * 255.0f + 0.01f ) ) ); - EP.aLDRPixels[i].g = uint8_t( std::max( 0.0f, std::min( 255.0f, pIn[i].g * 255.0f + 0.01f ) ) ); - EP.aLDRPixels[i].b = uint8_t( std::max( 0.0f, std::min( 255.0f, pIn[i].b * 255.0f + 0.01f ) ) ); - EP.aLDRPixels[i].a = uint8_t( std::max( 0.0f, std::min( 255.0f, pIn[i].a * 255.0f + 0.01f ) ) ); + EP.aLDRPixels[i].r = uint8_t(std::max(0.0f, std::min(255.0f, pIn[i].r * 255.0f + 0.01f))); + EP.aLDRPixels[i].g = uint8_t(std::max(0.0f, std::min(255.0f, pIn[i].g * 255.0f + 0.01f))); + EP.aLDRPixels[i].b = uint8_t(std::max(0.0f, std::min(255.0f, pIn[i].b * 255.0f + 0.01f))); + EP.aLDRPixels[i].a = uint8_t(std::max(0.0f, std::min(255.0f, pIn[i].a * 255.0f + 0.01f))); } - for(EP.uMode = 0; EP.uMode < 8 && fMSEBest > 0; ++EP.uMode) + for (EP.uMode = 0; EP.uMode < 8 && fMSEBest > 0; ++EP.uMode) { - if ( skip3subsets && (EP.uMode == 0 || EP.uMode == 2) ) + if (skip3subsets && (EP.uMode == 0 || EP.uMode == 2)) { // 3 subset modes tend to be used rarely and add significant compression time continue; } const size_t uShapes = size_t(1) << ms_aInfo[EP.uMode].uPartitionBits; - assert( uShapes <= BC7_MAX_SHAPES ); - _Analysis_assume_( uShapes <= BC7_MAX_SHAPES ); + assert(uShapes <= BC7_MAX_SHAPES); + _Analysis_assume_(uShapes <= BC7_MAX_SHAPES); const size_t uNumRots = size_t(1) << ms_aInfo[EP.uMode].uRotationBits; const size_t uNumIdxMode = size_t(1) << ms_aInfo[EP.uMode].uIndexModeBits; @@ -2179,30 +2212,30 @@ void D3DX_BC7::Encode(bool skip3subsets, const HDRColorA* const pIn) float afRoughMSE[BC7_MAX_SHAPES]; size_t auShape[BC7_MAX_SHAPES]; - for(size_t r = 0; r < uNumRots && fMSEBest > 0; ++r) + for (size_t r = 0; r < uNumRots && fMSEBest > 0; ++r) { - switch(r) + switch (r) { - case 1: for(register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].r, EP.aLDRPixels[i].a); break; - case 2: for(register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].g, EP.aLDRPixels[i].a); break; - case 3: for(register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].b, EP.aLDRPixels[i].a); break; + case 1: for (register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].r, EP.aLDRPixels[i].a); break; + case 2: for (register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].g, EP.aLDRPixels[i].a); break; + case 3: for (register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].b, EP.aLDRPixels[i].a); break; } - for(size_t im = 0; im < uNumIdxMode && fMSEBest > 0; ++im) + for (size_t im = 0; im < uNumIdxMode && fMSEBest > 0; ++im) { // pick the best uItems shapes and refine these. - for(size_t s = 0; s < uShapes; s++) + for (size_t s = 0; s < uShapes; s++) { afRoughMSE[s] = RoughMSE(&EP, s, im); auShape[s] = s; } // Bubble up the first uItems items - for(size_t i = 0; i < uItems; i++) + for (size_t i = 0; i < uItems; i++) { - for(size_t j = i + 1; j < uShapes; j++) + for (size_t j = i + 1; j < uShapes; j++) { - if(afRoughMSE[i] > afRoughMSE[j]) + if (afRoughMSE[i] > afRoughMSE[j]) { std::swap(afRoughMSE[i], afRoughMSE[j]); std::swap(auShape[i], auShape[j]); @@ -2210,10 +2243,10 @@ void D3DX_BC7::Encode(bool skip3subsets, const HDRColorA* const pIn) } } - for(size_t i = 0; i < uItems && fMSEBest > 0; i++) + for (size_t i = 0; i < uItems && fMSEBest > 0; i++) { float fMSE = Refine(&EP, auShape[i], r, im); - if(fMSE < fMSEBest) + if (fMSE < fMSEBest) { final = *this; fMSEBest = fMSE; @@ -2221,11 +2254,11 @@ void D3DX_BC7::Encode(bool skip3subsets, const HDRColorA* const pIn) } } - switch(r) + switch (r) { - case 1: for(register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].r, EP.aLDRPixels[i].a); break; - case 2: for(register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].g, EP.aLDRPixels[i].a); break; - case 3: for(register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].b, EP.aLDRPixels[i].a); break; + case 1: for (register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].r, EP.aLDRPixels[i].a); break; + case 2: for (register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].g, EP.aLDRPixels[i].a); break; + case 3: for (register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].b, EP.aLDRPixels[i].a); break; } } } @@ -2238,37 +2271,37 @@ void D3DX_BC7::Encode(bool skip3subsets, const HDRColorA* const pIn) _Use_decl_annotations_ void D3DX_BC7::GeneratePaletteQuantized(const EncodeParams* pEP, size_t uIndexMode, const LDREndPntPair& endPts, LDRColorA aPalette[]) const { - assert( pEP ); + assert(pEP); const size_t uIndexPrec = uIndexMode ? ms_aInfo[pEP->uMode].uIndexPrec2 : ms_aInfo[pEP->uMode].uIndexPrec; const size_t uIndexPrec2 = uIndexMode ? ms_aInfo[pEP->uMode].uIndexPrec : ms_aInfo[pEP->uMode].uIndexPrec2; const size_t uNumIndices = size_t(1) << uIndexPrec; const size_t uNumIndices2 = size_t(1) << uIndexPrec2; - assert( uNumIndices > 0 && uNumIndices2 > 0 ); - _Analysis_assume_( uNumIndices > 0 && uNumIndices2 > 0 ); - assert( (uNumIndices <= BC7_MAX_INDICES) && (uNumIndices2 <= BC7_MAX_INDICES) ); - _Analysis_assume_( (uNumIndices <= BC7_MAX_INDICES) && (uNumIndices2 <= BC7_MAX_INDICES) ); + assert(uNumIndices > 0 && uNumIndices2 > 0); + _Analysis_assume_(uNumIndices > 0 && uNumIndices2 > 0); + assert((uNumIndices <= BC7_MAX_INDICES) && (uNumIndices2 <= BC7_MAX_INDICES)); + _Analysis_assume_((uNumIndices <= BC7_MAX_INDICES) && (uNumIndices2 <= BC7_MAX_INDICES)); LDRColorA a = Unquantize(endPts.A, ms_aInfo[pEP->uMode].RGBAPrecWithP); LDRColorA b = Unquantize(endPts.B, ms_aInfo[pEP->uMode].RGBAPrecWithP); - if(uIndexPrec2 == 0) + if (uIndexPrec2 == 0) { - for(register size_t i = 0; i < uNumIndices; i++) + for (register size_t i = 0; i < uNumIndices; i++) LDRColorA::Interpolate(a, b, i, i, uIndexPrec, uIndexPrec, aPalette[i]); } else { - for(register size_t i = 0; i < uNumIndices; i++) + for (register size_t i = 0; i < uNumIndices; i++) LDRColorA::InterpolateRGB(a, b, i, uIndexPrec, aPalette[i]); - for(register size_t i = 0; i < uNumIndices2; i++) + for (register size_t i = 0; i < uNumIndices2; i++) LDRColorA::InterpolateA(a, b, i, uIndexPrec2, aPalette[i]); } } _Use_decl_annotations_ float D3DX_BC7::PerturbOne(const EncodeParams* pEP, const LDRColorA aColors[], size_t np, size_t uIndexMode, size_t ch, - const LDREndPntPair &oldEndPts, LDREndPntPair &newEndPts, float fOldErr, uint8_t do_b) const + const LDREndPntPair &oldEndPts, LDREndPntPair &newEndPts, float fOldErr, uint8_t do_b) const { - assert( pEP ); + assert(pEP); const int prec = ms_aInfo[pEP->uMode].RGBAPrecWithP[ch]; LDREndPntPair tmp_endPts = newEndPts = oldEndPts; float fMinErr = fOldErr; @@ -2276,20 +2309,20 @@ float D3DX_BC7::PerturbOne(const EncodeParams* pEP, const LDRColorA aColors[], s uint8_t* ptmp_c = (do_b ? &tmp_endPts.B[ch] : &tmp_endPts.A[ch]); // do a logarithmic search for the best error for this endpoint (which) - for(int step = 1 << (prec-1); step; step >>= 1) + for (int step = 1 << (prec - 1); step; step >>= 1) { bool bImproved = false; int beststep = 0; - for(int sign = -1; sign <= 1; sign += 2) + for (int sign = -1; sign <= 1; sign += 2) { int tmp = int(*pnew_c) + sign * step; - if(tmp < 0 || tmp >= (1 << prec)) + if (tmp < 0 || tmp >= (1 << prec)) continue; else - *ptmp_c = (uint8_t) tmp; + *ptmp_c = (uint8_t)tmp; float fTotalErr = MapColors(pEP, aColors, np, uIndexMode, tmp_endPts, fMinErr); - if(fTotalErr < fMinErr) + if (fTotalErr < fMinErr) { bImproved = true; fMinErr = fTotalErr; @@ -2298,7 +2331,7 @@ float D3DX_BC7::PerturbOne(const EncodeParams* pEP, const LDRColorA aColors[], s } // if this was an improvement, move the endpoint and continue search from there - if(bImproved) + if (bImproved) *pnew_c = uint8_t(int(*pnew_c) + beststep); } return fMinErr; @@ -2308,12 +2341,12 @@ float D3DX_BC7::PerturbOne(const EncodeParams* pEP, const LDRColorA aColors[], s // always ensure endpoint ordering is preserved (no need to overlap the scan) _Use_decl_annotations_ void D3DX_BC7::Exhaustive(const EncodeParams* pEP, const LDRColorA aColors[], size_t np, size_t uIndexMode, size_t ch, - float& fOrgErr, LDREndPntPair& optEndPt) const + float& fOrgErr, LDREndPntPair& optEndPt) const { - assert( pEP ); + assert(pEP); const uint8_t uPrec = ms_aInfo[pEP->uMode].RGBAPrecWithP[ch]; LDREndPntPair tmpEndPt; - if(fOrgErr == 0) + if (fOrgErr == 0) return; int delta = 5; @@ -2328,18 +2361,18 @@ void D3DX_BC7::Exhaustive(const EncodeParams* pEP, const LDRColorA aColors[], si int bmin = 0; float fBestErr = fOrgErr; - if(optEndPt.A[ch] <= optEndPt.B[ch]) + if (optEndPt.A[ch] <= optEndPt.B[ch]) { // keep a <= b - for(int a = alow; a <= ahigh; ++a) + for (int a = alow; a <= ahigh; ++a) { - for(int b = std::max(a, blow); b < bhigh; ++b) + for (int b = std::max(a, blow); b < bhigh; ++b) { - tmpEndPt.A[ch] = (uint8_t) a; - tmpEndPt.B[ch] = (uint8_t) b; + tmpEndPt.A[ch] = (uint8_t)a; + tmpEndPt.B[ch] = (uint8_t)b; float fErr = MapColors(pEP, aColors, np, uIndexMode, tmpEndPt, fBestErr); - if(fErr < fBestErr) + if (fErr < fBestErr) { amin = a; bmin = b; @@ -2351,15 +2384,15 @@ void D3DX_BC7::Exhaustive(const EncodeParams* pEP, const LDRColorA aColors[], si else { // keep b <= a - for(int b = blow; b < bhigh; ++b) + for (int b = blow; b < bhigh; ++b) { - for(int a = std::max(b, alow); a <= ahigh; ++a) + for (int a = std::max(b, alow); a <= ahigh; ++a) { - tmpEndPt.A[ch] = (uint8_t) a; - tmpEndPt.B[ch] = (uint8_t) b; + tmpEndPt.A[ch] = (uint8_t)a; + tmpEndPt.B[ch] = (uint8_t)b; float fErr = MapColors(pEP, aColors, np, uIndexMode, tmpEndPt, fBestErr); - if(fErr < fBestErr) + if (fErr < fBestErr) { amin = a; bmin = b; @@ -2369,19 +2402,19 @@ void D3DX_BC7::Exhaustive(const EncodeParams* pEP, const LDRColorA aColors[], si } } - if(fBestErr < fOrgErr) + if (fBestErr < fOrgErr) { - optEndPt.A[ch] = (uint8_t) amin; - optEndPt.B[ch] = (uint8_t) bmin; + optEndPt.A[ch] = (uint8_t)amin; + optEndPt.B[ch] = (uint8_t)bmin; fOrgErr = fBestErr; } } _Use_decl_annotations_ void D3DX_BC7::OptimizeOne(const EncodeParams* pEP, const LDRColorA aColors[], size_t np, size_t uIndexMode, - float fOrgErr, const LDREndPntPair& org, LDREndPntPair& opt) const + float fOrgErr, const LDREndPntPair& org, LDREndPntPair& opt) const { - assert( pEP ); + assert(pEP); float fOptErr = fOrgErr; opt = org; @@ -2391,9 +2424,9 @@ void D3DX_BC7::OptimizeOne(const EncodeParams* pEP, const LDRColorA aColors[], s uint8_t do_b; // now optimize each channel separately - for(size_t ch = 0; ch < BC7_NUM_CHANNELS; ++ch) + for (size_t ch = 0; ch < BC7_NUM_CHANNELS; ++ch) { - if(ms_aInfo[pEP->uMode].RGBAPrecWithP[ch] == 0) + if (ms_aInfo[pEP->uMode].RGBAPrecWithP[ch] == 0) continue; // figure out which endpoint when perturbed gives the most improvement and start there @@ -2406,9 +2439,9 @@ void D3DX_BC7::OptimizeOne(const EncodeParams* pEP, const LDRColorA aColors[], s uint8_t& cnew_a = new_a.A[ch]; uint8_t& cnew_b = new_a.B[ch]; - if(fErr0 < fErr1) + if (fErr0 < fErr1) { - if(fErr0 >= fOptErr) + if (fErr0 >= fOptErr) continue; copt_a = cnew_a; fOptErr = fErr0; @@ -2416,7 +2449,7 @@ void D3DX_BC7::OptimizeOne(const EncodeParams* pEP, const LDRColorA aColors[], s } else { - if(fErr1 >= fOptErr) + if (fErr1 >= fOptErr) continue; copt_b = cnew_b; fOptErr = fErr1; @@ -2424,12 +2457,12 @@ void D3DX_BC7::OptimizeOne(const EncodeParams* pEP, const LDRColorA aColors[], s } // now alternate endpoints and keep trying until there is no improvement - for( ; ; ) + for (; ; ) { float fErr = PerturbOne(pEP, aColors, np, uIndexMode, ch, opt, newEndPts, fOptErr, do_b); - if(fErr >= fOptErr) + if (fErr >= fOptErr) break; - if(do_b == 0) + if (do_b == 0) copt_a = cnew_a; else copt_b = cnew_b; @@ -2439,27 +2472,27 @@ void D3DX_BC7::OptimizeOne(const EncodeParams* pEP, const LDRColorA aColors[], s } // finally, do a small exhaustive search around what we think is the global minima to be sure - for(size_t ch = 0; ch < BC7_NUM_CHANNELS; ch++) + for (size_t ch = 0; ch < BC7_NUM_CHANNELS; ch++) Exhaustive(pEP, aColors, np, uIndexMode, ch, fOptErr, opt); } _Use_decl_annotations_ void D3DX_BC7::OptimizeEndPoints(const EncodeParams* pEP, size_t uShape, size_t uIndexMode, const float afOrgErr[], - const LDREndPntPair aOrgEndPts[], LDREndPntPair aOptEndPts[]) const + const LDREndPntPair aOrgEndPts[], LDREndPntPair aOptEndPts[]) const { - assert( pEP ); + assert(pEP); const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions; - assert( uPartitions < BC7_MAX_REGIONS && uShape < BC7_MAX_SHAPES ); - _Analysis_assume_( uPartitions < BC7_MAX_REGIONS && uShape < BC7_MAX_SHAPES ); + assert(uPartitions < BC7_MAX_REGIONS && uShape < BC7_MAX_SHAPES); + _Analysis_assume_(uPartitions < BC7_MAX_REGIONS && uShape < BC7_MAX_SHAPES); LDRColorA aPixels[NUM_PIXELS_PER_BLOCK]; - for(size_t p = 0; p <= uPartitions; ++p) + for (size_t p = 0; p <= uPartitions; ++p) { // collect the pixels in the region size_t np = 0; - for(register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) - if(g_aPartitionTable[uPartitions][uShape][i] == p) + for (register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + if (g_aPartitionTable[uPartitions][uShape][i] == p) aPixels[np++] = pEP->aLDRPixels[i]; OptimizeOne(pEP, aPixels, np, uIndexMode, afOrgErr[p], aOrgEndPts[p], aOptEndPts[p]); @@ -2468,53 +2501,53 @@ void D3DX_BC7::OptimizeEndPoints(const EncodeParams* pEP, size_t uShape, size_t _Use_decl_annotations_ void D3DX_BC7::AssignIndices(const EncodeParams* pEP, size_t uShape, size_t uIndexMode, LDREndPntPair endPts[], size_t aIndices[], size_t aIndices2[], - float afTotErr[]) const + float afTotErr[]) const { - assert( pEP ); - assert( uShape < BC7_MAX_SHAPES ); - _Analysis_assume_( uShape < BC7_MAX_SHAPES ); + assert(pEP); + assert(uShape < BC7_MAX_SHAPES); + _Analysis_assume_(uShape < BC7_MAX_SHAPES); const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions; - assert( uPartitions < BC7_MAX_REGIONS ); - _Analysis_assume_( uPartitions < BC7_MAX_REGIONS ); + assert(uPartitions < BC7_MAX_REGIONS); + _Analysis_assume_(uPartitions < BC7_MAX_REGIONS); const uint8_t uIndexPrec = uIndexMode ? ms_aInfo[pEP->uMode].uIndexPrec2 : ms_aInfo[pEP->uMode].uIndexPrec; const uint8_t uIndexPrec2 = uIndexMode ? ms_aInfo[pEP->uMode].uIndexPrec : ms_aInfo[pEP->uMode].uIndexPrec2; const uint8_t uNumIndices = 1 << uIndexPrec; const uint8_t uNumIndices2 = 1 << uIndexPrec2; - assert( (uNumIndices <= BC7_MAX_INDICES) && (uNumIndices2 <= BC7_MAX_INDICES) ); - _Analysis_assume_( (uNumIndices <= BC7_MAX_INDICES) && (uNumIndices2 <= BC7_MAX_INDICES) ); + assert((uNumIndices <= BC7_MAX_INDICES) && (uNumIndices2 <= BC7_MAX_INDICES)); + _Analysis_assume_((uNumIndices <= BC7_MAX_INDICES) && (uNumIndices2 <= BC7_MAX_INDICES)); const uint8_t uHighestIndexBit = uNumIndices >> 1; const uint8_t uHighestIndexBit2 = uNumIndices2 >> 1; LDRColorA aPalette[BC7_MAX_REGIONS][BC7_MAX_INDICES]; // build list of possibles - for(size_t p = 0; p <= uPartitions; p++) + for (size_t p = 0; p <= uPartitions; p++) { GeneratePaletteQuantized(pEP, uIndexMode, endPts[p], aPalette[p]); afTotErr[p] = 0; } - for(register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) + for (register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) { uint8_t uRegion = g_aPartitionTable[uPartitions][uShape][i]; - assert( uRegion < BC7_MAX_REGIONS ); - _Analysis_assume_( uRegion < BC7_MAX_REGIONS ); + assert(uRegion < BC7_MAX_REGIONS); + _Analysis_assume_(uRegion < BC7_MAX_REGIONS); afTotErr[uRegion] += ComputeError(pEP->aLDRPixels[i], aPalette[uRegion], uIndexPrec, uIndexPrec2, &(aIndices[i]), &(aIndices2[i])); } // swap endpoints as needed to ensure that the indices at index_positions have a 0 high-order bit - if(uIndexPrec2 == 0) + if (uIndexPrec2 == 0) { - for(register size_t p = 0; p <= uPartitions; p++) + for (register size_t p = 0; p <= uPartitions; p++) { - if(aIndices[g_aFixUp[uPartitions][uShape][p]] & uHighestIndexBit) + if (aIndices[g_aFixUp[uPartitions][uShape][p]] & uHighestIndexBit) { std::swap(endPts[p].A, endPts[p].B); - for(register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) - if(g_aPartitionTable[uPartitions][uShape][i] == p) + for (register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) + if (g_aPartitionTable[uPartitions][uShape][i] == p) aIndices[i] = uNumIndices - 1 - aIndices[i]; } assert((aIndices[g_aFixUp[uPartitions][uShape][p]] & uHighestIndexBit) == 0); @@ -2522,23 +2555,23 @@ void D3DX_BC7::AssignIndices(const EncodeParams* pEP, size_t uShape, size_t uInd } else { - for(register size_t p = 0; p <= uPartitions; p++) + for (register size_t p = 0; p <= uPartitions; p++) { - if(aIndices[g_aFixUp[uPartitions][uShape][p]] & uHighestIndexBit) + if (aIndices[g_aFixUp[uPartitions][uShape][p]] & uHighestIndexBit) { std::swap(endPts[p].A.r, endPts[p].B.r); std::swap(endPts[p].A.g, endPts[p].B.g); std::swap(endPts[p].A.b, endPts[p].B.b); - for(register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) - if(g_aPartitionTable[uPartitions][uShape][i] == p) + for (register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) + if (g_aPartitionTable[uPartitions][uShape][i] == p) aIndices[i] = uNumIndices - 1 - aIndices[i]; } assert((aIndices[g_aFixUp[uPartitions][uShape][p]] & uHighestIndexBit) == 0); - if(aIndices2[0] & uHighestIndexBit2) + if (aIndices2[0] & uHighestIndexBit2) { std::swap(endPts[p].A.a, endPts[p].B.a); - for(register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) + for (register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) aIndices2[i] = uNumIndices2 - 1 - aIndices2[i]; } assert((aIndices2[0] & uHighestIndexBit2) == 0); @@ -2549,10 +2582,10 @@ void D3DX_BC7::AssignIndices(const EncodeParams* pEP, size_t uShape, size_t uInd _Use_decl_annotations_ void D3DX_BC7::EmitBlock(const EncodeParams* pEP, size_t uShape, size_t uRotation, size_t uIndexMode, const LDREndPntPair aEndPts[], const size_t aIndex[], const size_t aIndex2[]) { - assert( pEP ); + assert(pEP); const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions; - assert( uPartitions < BC7_MAX_REGIONS ); - _Analysis_assume_( uPartitions < BC7_MAX_REGIONS ); + assert(uPartitions < BC7_MAX_REGIONS); + _Analysis_assume_(uPartitions < BC7_MAX_REGIONS); const size_t uPBits = ms_aInfo[pEP->uMode].uPBits; const size_t uIndexPrec = ms_aInfo[pEP->uMode].uIndexPrec; @@ -2563,21 +2596,21 @@ void D3DX_BC7::EmitBlock(const EncodeParams* pEP, size_t uShape, size_t uRotatio size_t uStartBit = 0; SetBits(uStartBit, pEP->uMode, 0); SetBits(uStartBit, 1, 1); - SetBits(uStartBit, ms_aInfo[pEP->uMode].uRotationBits, static_cast( uRotation )); - SetBits(uStartBit, ms_aInfo[pEP->uMode].uIndexModeBits, static_cast( uIndexMode )); - SetBits(uStartBit, ms_aInfo[pEP->uMode].uPartitionBits, static_cast( uShape )); + SetBits(uStartBit, ms_aInfo[pEP->uMode].uRotationBits, static_cast(uRotation)); + SetBits(uStartBit, ms_aInfo[pEP->uMode].uIndexModeBits, static_cast(uIndexMode)); + SetBits(uStartBit, ms_aInfo[pEP->uMode].uPartitionBits, static_cast(uShape)); - if(uPBits) + if (uPBits) { const size_t uNumEP = size_t(1 + uPartitions) << 1; - uint8_t aPVote[BC7_MAX_REGIONS << 1] = {0,0,0,0,0,0}; - uint8_t aCount[BC7_MAX_REGIONS << 1] = {0,0,0,0,0,0}; - for(uint8_t ch = 0; ch < BC7_NUM_CHANNELS; ch++) + uint8_t aPVote[BC7_MAX_REGIONS << 1] = { 0,0,0,0,0,0 }; + uint8_t aCount[BC7_MAX_REGIONS << 1] = { 0,0,0,0,0,0 }; + for (uint8_t ch = 0; ch < BC7_NUM_CHANNELS; ch++) { uint8_t ep = 0; - for(i = 0; i <= uPartitions; i++) + for (i = 0; i <= uPartitions; i++) { - if(RGBAPrec[ch] == RGBAPrecWithP[ch]) + if (RGBAPrec[ch] == RGBAPrecWithP[ch]) { SetBits(uStartBit, RGBAPrec[ch], aEndPts[i].A[ch]); SetBits(uStartBit, RGBAPrec[ch], aEndPts[i].B[ch]); @@ -2600,35 +2633,35 @@ void D3DX_BC7::EmitBlock(const EncodeParams* pEP, size_t uShape, size_t uRotatio } } - for(i = 0; i < uPBits; i++) + for (i = 0; i < uPBits; i++) { SetBits(uStartBit, 1, aPVote[i] > (aCount[i] >> 1) ? 1 : 0); } } else { - for(size_t ch = 0; ch < BC7_NUM_CHANNELS; ch++) + for (size_t ch = 0; ch < BC7_NUM_CHANNELS; ch++) { - for(i = 0; i <= uPartitions; i++) + for (i = 0; i <= uPartitions; i++) { - SetBits(uStartBit, RGBAPrec[ch], aEndPts[i].A[ch] ); - SetBits(uStartBit, RGBAPrec[ch], aEndPts[i].B[ch] ); + SetBits(uStartBit, RGBAPrec[ch], aEndPts[i].A[ch]); + SetBits(uStartBit, RGBAPrec[ch], aEndPts[i].B[ch]); } } } const size_t* aI1 = uIndexMode ? aIndex2 : aIndex; const size_t* aI2 = uIndexMode ? aIndex : aIndex2; - for(i = 0; i < NUM_PIXELS_PER_BLOCK; i++) + for (i = 0; i < NUM_PIXELS_PER_BLOCK; i++) { - if(IsFixUpOffset(ms_aInfo[pEP->uMode].uPartitions, uShape, i)) - SetBits(uStartBit, uIndexPrec - 1, static_cast( aI1[i] )); + if (IsFixUpOffset(ms_aInfo[pEP->uMode].uPartitions, uShape, i)) + SetBits(uStartBit, uIndexPrec - 1, static_cast(aI1[i])); else - SetBits(uStartBit, uIndexPrec, static_cast( aI1[i] )); + SetBits(uStartBit, uIndexPrec, static_cast(aI1[i])); } - if(uIndexPrec2) - for(i = 0; i < NUM_PIXELS_PER_BLOCK; i++) - SetBits(uStartBit, i ? uIndexPrec2 : uIndexPrec2 - 1, static_cast( aI2[i] )); + if (uIndexPrec2) + for (i = 0; i < NUM_PIXELS_PER_BLOCK; i++) + SetBits(uStartBit, i ? uIndexPrec2 : uIndexPrec2 - 1, static_cast(aI2[i])); assert(uStartBit == 128); } @@ -2685,17 +2718,17 @@ float D3DX_BC7::Refine(const EncodeParams* pEP, size_t uShape, size_t uRotation, _Use_decl_annotations_ float D3DX_BC7::MapColors(const EncodeParams* pEP, const LDRColorA aColors[], size_t np, size_t uIndexMode, const LDREndPntPair& endPts, float fMinErr) const { - assert( pEP ); + assert(pEP); const uint8_t uIndexPrec = uIndexMode ? ms_aInfo[pEP->uMode].uIndexPrec2 : ms_aInfo[pEP->uMode].uIndexPrec; const uint8_t uIndexPrec2 = uIndexMode ? ms_aInfo[pEP->uMode].uIndexPrec : ms_aInfo[pEP->uMode].uIndexPrec2; LDRColorA aPalette[BC7_MAX_INDICES]; float fTotalErr = 0; GeneratePaletteQuantized(pEP, uIndexMode, endPts, aPalette); - for(register size_t i = 0; i < np; ++i) + for (register size_t i = 0; i < np; ++i) { fTotalErr += ComputeError(aColors[i], aPalette, uIndexPrec, uIndexPrec2); - if(fTotalErr > fMinErr) // check for early exit + if (fTotalErr > fMinErr) // check for early exit { fTotalErr = FLT_MAX; break; @@ -2708,14 +2741,14 @@ float D3DX_BC7::MapColors(const EncodeParams* pEP, const LDRColorA aColors[], si _Use_decl_annotations_ float D3DX_BC7::RoughMSE(EncodeParams* pEP, size_t uShape, size_t uIndexMode) { - assert( pEP ); - assert( uShape < BC7_MAX_SHAPES ); - _Analysis_assume_( uShape < BC7_MAX_SHAPES ); + assert(pEP); + assert(uShape < BC7_MAX_SHAPES); + _Analysis_assume_(uShape < BC7_MAX_SHAPES); LDREndPntPair* aEndPts = pEP->aEndPts[uShape]; const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions; - assert( uPartitions < BC7_MAX_REGIONS ); - _Analysis_assume_( uPartitions < BC7_MAX_REGIONS ); + assert(uPartitions < BC7_MAX_REGIONS); + _Analysis_assume_(uPartitions < BC7_MAX_REGIONS); const uint8_t uIndexPrec = uIndexMode ? ms_aInfo[pEP->uMode].uIndexPrec2 : ms_aInfo[pEP->uMode].uIndexPrec; const uint8_t uIndexPrec2 = uIndexMode ? ms_aInfo[pEP->uMode].uIndexPrec : ms_aInfo[pEP->uMode].uIndexPrec2; @@ -2724,10 +2757,10 @@ float D3DX_BC7::RoughMSE(EncodeParams* pEP, size_t uShape, size_t uIndexMode) size_t auPixIdx[NUM_PIXELS_PER_BLOCK]; LDRColorA aPalette[BC7_MAX_REGIONS][BC7_MAX_INDICES]; - for(size_t p = 0; p <= uPartitions; p++) + for (size_t p = 0; p <= uPartitions; p++) { size_t np = 0; - for(register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) + for (register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) { if (g_aPartitionTable[uPartitions][uShape][i] == p) { @@ -2737,20 +2770,20 @@ float D3DX_BC7::RoughMSE(EncodeParams* pEP, size_t uShape, size_t uIndexMode) // handle simple cases assert(np > 0); - if(np == 1) + if (np == 1) { aEndPts[p].A = pEP->aLDRPixels[auPixIdx[0]]; aEndPts[p].B = pEP->aLDRPixels[auPixIdx[0]]; continue; } - else if(np == 2) + else if (np == 2) { aEndPts[p].A = pEP->aLDRPixels[auPixIdx[0]]; aEndPts[p].B = pEP->aLDRPixels[auPixIdx[1]]; continue; } - if(uIndexPrec2 == 0) + if (uIndexPrec2 == 0) { HDRColorA epA, epB; OptimizeRGBA(pEP->aHDRPixels, &epA, &epB, 4, np, auPixIdx); @@ -2764,7 +2797,7 @@ float D3DX_BC7::RoughMSE(EncodeParams* pEP, size_t uShape, size_t uIndexMode) else { uint8_t uMinAlpha = 255, uMaxAlpha = 0; - for(register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) + for (register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i) { uMinAlpha = std::min(uMinAlpha, pEP->aLDRPixels[auPixIdx[i]].a); uMaxAlpha = std::max(uMaxAlpha, pEP->aLDRPixels[auPixIdx[i]].a); @@ -2783,25 +2816,25 @@ float D3DX_BC7::RoughMSE(EncodeParams* pEP, size_t uShape, size_t uIndexMode) } } - if(uIndexPrec2 == 0) + if (uIndexPrec2 == 0) { - for(size_t p = 0; p <= uPartitions; p++) - for(register size_t i = 0; i < uNumIndices; i++) + for (size_t p = 0; p <= uPartitions; p++) + for (register size_t i = 0; i < uNumIndices; i++) LDRColorA::Interpolate(aEndPts[p].A, aEndPts[p].B, i, i, uIndexPrec, uIndexPrec, aPalette[p][i]); } else { - for(size_t p = 0; p <= uPartitions; p++) + for (size_t p = 0; p <= uPartitions; p++) { - for(register size_t i = 0; i < uNumIndices; i++) + for (register size_t i = 0; i < uNumIndices; i++) LDRColorA::InterpolateRGB(aEndPts[p].A, aEndPts[p].B, i, uIndexPrec, aPalette[p][i]); - for(register size_t i = 0; i < uNumIndices2; i++) + for (register size_t i = 0; i < uNumIndices2; i++) LDRColorA::InterpolateA(aEndPts[p].A, aEndPts[p].B, i, uIndexPrec2, aPalette[p][i]); } } float fTotalErr = 0; - for(register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) + for (register size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) { uint8_t uRegion = g_aPartitionTable[uPartitions][uShape][i]; fTotalErr += ComputeError(pEP->aLDRPixels[i], aPalette[uRegion], uIndexPrec, uIndexPrec2); @@ -2810,6 +2843,7 @@ float D3DX_BC7::RoughMSE(EncodeParams* pEP, size_t uShape, size_t uIndexMode) return fTotalErr; } + //===================================================================================== // Entry points //===================================================================================== @@ -2818,37 +2852,37 @@ float D3DX_BC7::RoughMSE(EncodeParams* pEP, size_t uShape, size_t uIndexMode) // BC6H Compression //------------------------------------------------------------------------------------- _Use_decl_annotations_ -void D3DXDecodeBC6HU(XMVECTOR *pColor, const uint8_t *pBC) +void DirectX::D3DXDecodeBC6HU(XMVECTOR *pColor, const uint8_t *pBC) { - assert( pColor && pBC ); - static_assert( sizeof(D3DX_BC6H) == 16, "D3DX_BC6H should be 16 bytes" ); - reinterpret_cast< const D3DX_BC6H* >( pBC )->Decode(false, reinterpret_cast(pColor)); + assert(pColor && pBC); + static_assert(sizeof(D3DX_BC6H) == 16, "D3DX_BC6H should be 16 bytes"); + reinterpret_cast(pBC)->Decode(false, reinterpret_cast(pColor)); } _Use_decl_annotations_ -void D3DXDecodeBC6HS(XMVECTOR *pColor, const uint8_t *pBC) +void DirectX::D3DXDecodeBC6HS(XMVECTOR *pColor, const uint8_t *pBC) { - assert( pColor && pBC ); - static_assert( sizeof(D3DX_BC6H) == 16, "D3DX_BC6H should be 16 bytes" ); - reinterpret_cast< const D3DX_BC6H* >( pBC )->Decode(true, reinterpret_cast(pColor)); + assert(pColor && pBC); + static_assert(sizeof(D3DX_BC6H) == 16, "D3DX_BC6H should be 16 bytes"); + reinterpret_cast(pBC)->Decode(true, reinterpret_cast(pColor)); } _Use_decl_annotations_ -void D3DXEncodeBC6HU(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) +void DirectX::D3DXEncodeBC6HU(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) { UNREFERENCED_PARAMETER(flags); - assert( pBC && pColor ); - static_assert( sizeof(D3DX_BC6H) == 16, "D3DX_BC6H should be 16 bytes" ); - reinterpret_cast< D3DX_BC6H* >( pBC )->Encode(false, reinterpret_cast(pColor)); + assert(pBC && pColor); + static_assert(sizeof(D3DX_BC6H) == 16, "D3DX_BC6H should be 16 bytes"); + reinterpret_cast(pBC)->Encode(false, reinterpret_cast(pColor)); } _Use_decl_annotations_ -void D3DXEncodeBC6HS(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) +void DirectX::D3DXEncodeBC6HS(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) { UNREFERENCED_PARAMETER(flags); - assert( pBC && pColor ); - static_assert( sizeof(D3DX_BC6H) == 16, "D3DX_BC6H should be 16 bytes" ); - reinterpret_cast< D3DX_BC6H* >( pBC )->Encode(true, reinterpret_cast(pColor)); + assert(pBC && pColor); + static_assert(sizeof(D3DX_BC6H) == 16, "D3DX_BC6H should be 16 bytes"); + reinterpret_cast(pBC)->Encode(true, reinterpret_cast(pColor)); } @@ -2856,19 +2890,17 @@ void D3DXEncodeBC6HS(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) // BC7 Compression //------------------------------------------------------------------------------------- _Use_decl_annotations_ -void D3DXDecodeBC7(XMVECTOR *pColor, const uint8_t *pBC) +void DirectX::D3DXDecodeBC7(XMVECTOR *pColor, const uint8_t *pBC) { - assert( pColor && pBC ); - static_assert( sizeof(D3DX_BC7) == 16, "D3DX_BC7 should be 16 bytes" ); - reinterpret_cast< const D3DX_BC7* >( pBC )->Decode(reinterpret_cast(pColor)); + assert(pColor && pBC); + static_assert(sizeof(D3DX_BC7) == 16, "D3DX_BC7 should be 16 bytes"); + reinterpret_cast(pBC)->Decode(reinterpret_cast(pColor)); } _Use_decl_annotations_ -void D3DXEncodeBC7(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) +void DirectX::D3DXEncodeBC7(uint8_t *pBC, const XMVECTOR *pColor, DWORD flags) { - assert( pBC && pColor ); - static_assert( sizeof(D3DX_BC7) == 16, "D3DX_BC7 should be 16 bytes" ); - reinterpret_cast< D3DX_BC7* >( pBC )->Encode( !(flags& BC_FLAGS_USE_3SUBSETS), reinterpret_cast(pColor)); + assert(pBC && pColor); + static_assert(sizeof(D3DX_BC7) == 16, "D3DX_BC7 should be 16 bytes"); + reinterpret_cast(pBC)->Encode(!(flags& BC_FLAGS_USE_3SUBSETS), reinterpret_cast(pColor)); } - -} // namespace diff --git a/DirectXTex/BCDirectCompute.cpp b/DirectXTex/BCDirectCompute.cpp index c37dbeb..9f8e607 100644 --- a/DirectXTex/BCDirectCompute.cpp +++ b/DirectXTex/BCDirectCompute.cpp @@ -19,6 +19,7 @@ #pragma comment(lib,"dxguid.lib") #endif +using namespace DirectX; using Microsoft::WRL::ComPtr; namespace @@ -82,9 +83,6 @@ namespace } }; -namespace DirectX -{ - GPUCompressBC::GPUCompressBC() : m_bcformat(DXGI_FORMAT_UNKNOWN), m_srcformat(DXGI_FORMAT_UNKNOWN), @@ -97,79 +95,79 @@ GPUCompressBC::GPUCompressBC() : //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT GPUCompressBC::Initialize( ID3D11Device* pDevice ) +HRESULT GPUCompressBC::Initialize(ID3D11Device* pDevice) { - if ( !pDevice ) + if (!pDevice) return E_INVALIDARG; // Check for DirectCompute support D3D_FEATURE_LEVEL fl = pDevice->GetFeatureLevel(); - if ( fl < D3D_FEATURE_LEVEL_10_0 ) + if (fl < D3D_FEATURE_LEVEL_10_0) { // DirectCompute not supported on Feature Level 9.x hardware - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } - if ( fl < D3D_FEATURE_LEVEL_11_0 ) + if (fl < D3D_FEATURE_LEVEL_11_0) { // DirectCompute support on Feature Level 10.x hardware is optional, and this function needs it D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS hwopts; - HRESULT hr = pDevice->CheckFeatureSupport( D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS, &hwopts, sizeof(hwopts) ); - if ( FAILED(hr) ) + HRESULT hr = pDevice->CheckFeatureSupport(D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS, &hwopts, sizeof(hwopts)); + if (FAILED(hr)) { - memset( &hwopts, 0, sizeof(hwopts) ); + memset(&hwopts, 0, sizeof(hwopts)); } - if ( !hwopts.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x ) + if (!hwopts.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x) { - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } } // Save a device reference and obtain immediate context m_device = pDevice; - pDevice->GetImmediateContext( m_context.ReleaseAndGetAddressOf() ); - assert( m_context ); + pDevice->GetImmediateContext(m_context.ReleaseAndGetAddressOf()); + assert(m_context); //--- Create compute shader library: BC6H ----------------------------------------- // Modes 11-14 - HRESULT hr = pDevice->CreateComputeShader( BC6HEncode_TryModeG10CS, sizeof(BC6HEncode_TryModeG10CS), nullptr, m_BC6H_tryModeG10CS.ReleaseAndGetAddressOf() ); - if ( FAILED(hr) ) + HRESULT hr = pDevice->CreateComputeShader(BC6HEncode_TryModeG10CS, sizeof(BC6HEncode_TryModeG10CS), nullptr, m_BC6H_tryModeG10CS.ReleaseAndGetAddressOf()); + if (FAILED(hr)) return hr; // Modes 1-10 - hr = pDevice->CreateComputeShader( BC6HEncode_TryModeLE10CS, sizeof(BC6HEncode_TryModeLE10CS), nullptr, m_BC6H_tryModeLE10CS.ReleaseAndGetAddressOf() ); - if ( FAILED(hr) ) + hr = pDevice->CreateComputeShader(BC6HEncode_TryModeLE10CS, sizeof(BC6HEncode_TryModeLE10CS), nullptr, m_BC6H_tryModeLE10CS.ReleaseAndGetAddressOf()); + if (FAILED(hr)) return hr; // Encode - hr = pDevice->CreateComputeShader( BC6HEncode_EncodeBlockCS, sizeof(BC6HEncode_EncodeBlockCS), nullptr, m_BC6H_encodeBlockCS.ReleaseAndGetAddressOf() ); - if ( FAILED(hr) ) + hr = pDevice->CreateComputeShader(BC6HEncode_EncodeBlockCS, sizeof(BC6HEncode_EncodeBlockCS), nullptr, m_BC6H_encodeBlockCS.ReleaseAndGetAddressOf()); + if (FAILED(hr)) return hr; //--- Create compute shader library: BC7 ------------------------------------------ // Modes 4, 5, 6 - hr = pDevice->CreateComputeShader( BC7Encode_TryMode456CS, sizeof(BC7Encode_TryMode456CS), nullptr, m_BC7_tryMode456CS.ReleaseAndGetAddressOf() ); - if ( FAILED(hr) ) + hr = pDevice->CreateComputeShader(BC7Encode_TryMode456CS, sizeof(BC7Encode_TryMode456CS), nullptr, m_BC7_tryMode456CS.ReleaseAndGetAddressOf()); + if (FAILED(hr)) return hr; // Modes 1, 3, 7 - hr = pDevice->CreateComputeShader( BC7Encode_TryMode137CS, sizeof(BC7Encode_TryMode137CS), nullptr, m_BC7_tryMode137CS.ReleaseAndGetAddressOf() ); - if ( FAILED(hr) ) + hr = pDevice->CreateComputeShader(BC7Encode_TryMode137CS, sizeof(BC7Encode_TryMode137CS), nullptr, m_BC7_tryMode137CS.ReleaseAndGetAddressOf()); + if (FAILED(hr)) return hr; // Modes 0, 2 - hr = pDevice->CreateComputeShader( BC7Encode_TryMode02CS, sizeof(BC7Encode_TryMode02CS), nullptr, m_BC7_tryMode02CS.ReleaseAndGetAddressOf() ); - if ( FAILED(hr) ) + hr = pDevice->CreateComputeShader(BC7Encode_TryMode02CS, sizeof(BC7Encode_TryMode02CS), nullptr, m_BC7_tryMode02CS.ReleaseAndGetAddressOf()); + if (FAILED(hr)) return hr; // Encode - hr = pDevice->CreateComputeShader( BC7Encode_EncodeBlockCS, sizeof(BC7Encode_EncodeBlockCS), nullptr, m_BC7_encodeBlockCS.ReleaseAndGetAddressOf() ); - if ( FAILED(hr) ) + hr = pDevice->CreateComputeShader(BC7Encode_EncodeBlockCS, sizeof(BC7Encode_EncodeBlockCS), nullptr, m_BC7_encodeBlockCS.ReleaseAndGetAddressOf()); + if (FAILED(hr)) return hr; return S_OK; @@ -178,12 +176,12 @@ HRESULT GPUCompressBC::Initialize( ID3D11Device* pDevice ) //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT GPUCompressBC::Prepare( size_t width, size_t height, DXGI_FORMAT format, float alphaWeight, bool skip3subsets ) +HRESULT GPUCompressBC::Prepare(size_t width, size_t height, DXGI_FORMAT format, float alphaWeight, bool skip3subsets) { - if ( !width || !height || alphaWeight < 0.f ) + if (!width || !height || alphaWeight < 0.f) return E_INVALIDARG; - if ( (width > UINT32_MAX) || (height > UINT32_MAX) ) + if ((width > UINT32_MAX) || (height > UINT32_MAX)) return E_INVALIDARG; m_width = width; @@ -193,20 +191,20 @@ HRESULT GPUCompressBC::Prepare( size_t width, size_t height, DXGI_FORMAT format, m_skip3Subsets = skip3subsets; - size_t xblocks = std::max( 1, (width + 3) >> 2 ); - size_t yblocks = std::max( 1, (height + 3) >> 2 ); + size_t xblocks = std::max(1, (width + 3) >> 2); + size_t yblocks = std::max(1, (height + 3) >> 2); size_t num_blocks = xblocks * yblocks; - switch( format ) + switch (format) { - // BC6H GPU compressor takes RGBAF32 as input + // BC6H GPU compressor takes RGBAF32 as input case DXGI_FORMAT_BC6H_TYPELESS: case DXGI_FORMAT_BC6H_UF16: case DXGI_FORMAT_BC6H_SF16: m_srcformat = DXGI_FORMAT_R32G32B32A32_FLOAT; break; - // BC7 GPU compressor takes RGBA32 as input + // BC7 GPU compressor takes RGBA32 as input case DXGI_FORMAT_BC7_TYPELESS: case DXGI_FORMAT_BC7_UNORM: m_srcformat = DXGI_FORMAT_R8G8B8A8_UNORM; @@ -218,39 +216,39 @@ HRESULT GPUCompressBC::Prepare( size_t width, size_t height, DXGI_FORMAT format, default: m_bcformat = m_srcformat = DXGI_FORMAT_UNKNOWN; - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } m_bcformat = format; auto pDevice = m_device.Get(); - if ( !pDevice ) + if (!pDevice) return E_POINTER; // Create structured buffers - size_t bufferSize = num_blocks * sizeof( BufferBC6HBC7 ); + size_t bufferSize = num_blocks * sizeof(BufferBC6HBC7); { D3D11_BUFFER_DESC desc = {}; desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE; desc.Usage = D3D11_USAGE_DEFAULT; desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; - desc.StructureByteStride = sizeof( BufferBC6HBC7 ); - desc.ByteWidth = static_cast( bufferSize ); + desc.StructureByteStride = sizeof(BufferBC6HBC7); + desc.ByteWidth = static_cast(bufferSize); - HRESULT hr = pDevice->CreateBuffer( &desc, nullptr, m_output.ReleaseAndGetAddressOf() ); - if ( FAILED(hr) ) + HRESULT hr = pDevice->CreateBuffer(&desc, nullptr, m_output.ReleaseAndGetAddressOf()); + if (FAILED(hr)) { return hr; } - hr = pDevice->CreateBuffer( &desc, nullptr, m_err1.ReleaseAndGetAddressOf() ); - if ( FAILED(hr) ) + hr = pDevice->CreateBuffer(&desc, nullptr, m_err1.ReleaseAndGetAddressOf()); + if (FAILED(hr)) { return hr; } - hr = pDevice->CreateBuffer( &desc, nullptr, m_err2.ReleaseAndGetAddressOf() ); - if ( FAILED(hr) ) + hr = pDevice->CreateBuffer(&desc, nullptr, m_err2.ReleaseAndGetAddressOf()); + if (FAILED(hr)) { return hr; } @@ -261,10 +259,10 @@ HRESULT GPUCompressBC::Prepare( size_t width, size_t height, DXGI_FORMAT format, D3D11_BUFFER_DESC desc = {}; desc.Usage = D3D11_USAGE_STAGING; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - desc.ByteWidth = static_cast( bufferSize ); + desc.ByteWidth = static_cast(bufferSize); - HRESULT hr = pDevice->CreateBuffer( &desc, nullptr, m_outputCPU.ReleaseAndGetAddressOf() ); - if ( FAILED(hr) ) + HRESULT hr = pDevice->CreateBuffer(&desc, nullptr, m_outputCPU.ReleaseAndGetAddressOf()); + if (FAILED(hr)) { return hr; } @@ -276,10 +274,10 @@ HRESULT GPUCompressBC::Prepare( size_t width, size_t height, DXGI_FORMAT format, desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; desc.Usage = D3D11_USAGE_DYNAMIC; desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - desc.ByteWidth = sizeof( ConstantsBC6HBC7 ); + desc.ByteWidth = sizeof(ConstantsBC6HBC7); - HRESULT hr = pDevice->CreateBuffer( &desc, nullptr, m_constBuffer.ReleaseAndGetAddressOf() ); - if ( FAILED(hr) ) + HRESULT hr = pDevice->CreateBuffer(&desc, nullptr, m_constBuffer.ReleaseAndGetAddressOf()); + if (FAILED(hr)) { return hr; } @@ -288,17 +286,17 @@ HRESULT GPUCompressBC::Prepare( size_t width, size_t height, DXGI_FORMAT format, // Create shader resource views { D3D11_SHADER_RESOURCE_VIEW_DESC desc = {}; - desc.Buffer.NumElements = static_cast( num_blocks ); + desc.Buffer.NumElements = static_cast(num_blocks); desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; - HRESULT hr = pDevice->CreateShaderResourceView( m_err1.Get(), &desc, m_err1SRV.ReleaseAndGetAddressOf() ); - if ( FAILED(hr) ) + HRESULT hr = pDevice->CreateShaderResourceView(m_err1.Get(), &desc, m_err1SRV.ReleaseAndGetAddressOf()); + if (FAILED(hr)) { return hr; } - hr = pDevice->CreateShaderResourceView( m_err2.Get(), &desc, m_err2SRV.ReleaseAndGetAddressOf() ); - if ( FAILED(hr) ) + hr = pDevice->CreateShaderResourceView(m_err2.Get(), &desc, m_err2SRV.ReleaseAndGetAddressOf()); + if (FAILED(hr)) { return hr; } @@ -307,62 +305,62 @@ HRESULT GPUCompressBC::Prepare( size_t width, size_t height, DXGI_FORMAT format, // Create unordered access views { D3D11_UNORDERED_ACCESS_VIEW_DESC desc = {}; - desc.Buffer.NumElements = static_cast( num_blocks ); + desc.Buffer.NumElements = static_cast(num_blocks); desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; - HRESULT hr = pDevice->CreateUnorderedAccessView( m_output.Get(), &desc, m_outputUAV.ReleaseAndGetAddressOf() ); - if ( FAILED(hr) ) + HRESULT hr = pDevice->CreateUnorderedAccessView(m_output.Get(), &desc, m_outputUAV.ReleaseAndGetAddressOf()); + if (FAILED(hr)) { return hr; } - hr = pDevice->CreateUnorderedAccessView( m_err1.Get(), &desc, m_err1UAV.ReleaseAndGetAddressOf() ); - if ( FAILED(hr) ) + hr = pDevice->CreateUnorderedAccessView(m_err1.Get(), &desc, m_err1UAV.ReleaseAndGetAddressOf()); + if (FAILED(hr)) { return hr; } - hr = pDevice->CreateUnorderedAccessView( m_err2.Get(), &desc, m_err2UAV.ReleaseAndGetAddressOf() ); - if ( FAILED(hr) ) + hr = pDevice->CreateUnorderedAccessView(m_err2.Get(), &desc, m_err2UAV.ReleaseAndGetAddressOf()); + if (FAILED(hr)) { return hr; } } - + return S_OK; } //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT GPUCompressBC::Compress( const Image& srcImage, const Image& destImage ) +HRESULT GPUCompressBC::Compress(const Image& srcImage, const Image& destImage) { - if ( !srcImage.pixels || !destImage.pixels ) + if (!srcImage.pixels || !destImage.pixels) return E_INVALIDARG; - if ( srcImage.width != destImage.width - || srcImage.height != destImage.height - || srcImage.width != m_width - || srcImage.height != m_height - || srcImage.format != m_srcformat - || destImage.format != m_bcformat ) + if (srcImage.width != destImage.width + || srcImage.height != destImage.height + || srcImage.width != m_width + || srcImage.height != m_height + || srcImage.format != m_srcformat + || destImage.format != m_bcformat) { return E_UNEXPECTED; } //--- Create input texture -------------------------------------------------------- auto pDevice = m_device.Get(); - if ( !pDevice ) + if (!pDevice) return E_POINTER; // We need to avoid the hardware doing additional colorspace conversion - DXGI_FORMAT inputFormat = ( m_srcformat == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB ) ? DXGI_FORMAT_R8G8B8A8_UNORM : m_srcformat; + DXGI_FORMAT inputFormat = (m_srcformat == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) ? DXGI_FORMAT_R8G8B8A8_UNORM : m_srcformat; ComPtr sourceTex; { D3D11_TEXTURE2D_DESC desc = {}; - desc.Width = static_cast( srcImage.width ); - desc.Height = static_cast( srcImage.height ); + desc.Width = static_cast(srcImage.width); + desc.Height = static_cast(srcImage.height); desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = inputFormat; @@ -372,11 +370,11 @@ HRESULT GPUCompressBC::Compress( const Image& srcImage, const Image& destImage ) D3D11_SUBRESOURCE_DATA initData; initData.pSysMem = srcImage.pixels; - initData.SysMemPitch = static_cast( srcImage.rowPitch ); - initData.SysMemSlicePitch = static_cast( srcImage.slicePitch ); + initData.SysMemPitch = static_cast(srcImage.rowPitch); + initData.SysMemSlicePitch = static_cast(srcImage.slicePitch); - HRESULT hr = pDevice->CreateTexture2D( &desc, &initData, sourceTex.GetAddressOf() ); - if ( FAILED(hr) ) + HRESULT hr = pDevice->CreateTexture2D(&desc, &initData, sourceTex.GetAddressOf()); + if (FAILED(hr)) { return hr; } @@ -389,8 +387,8 @@ HRESULT GPUCompressBC::Compress( const Image& srcImage, const Image& destImage ) desc.Format = inputFormat; desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - HRESULT hr = pDevice->CreateShaderResourceView( sourceTex.Get(), &desc, sourceSRV.GetAddressOf() ); - if ( FAILED(hr) ) + HRESULT hr = pDevice->CreateShaderResourceView(sourceTex.Get(), &desc, sourceSRV.GetAddressOf()); + if (FAILED(hr)) { return hr; } @@ -398,7 +396,7 @@ HRESULT GPUCompressBC::Compress( const Image& srcImage, const Image& destImage ) //--- Compress using DirectCompute ------------------------------------------------ bool isbc7 = false; - switch( m_bcformat ) + switch (m_bcformat) { case DXGI_FORMAT_BC6H_TYPELESS: case DXGI_FORMAT_BC6H_UF16: @@ -418,47 +416,47 @@ HRESULT GPUCompressBC::Compress( const Image& srcImage, const Image& destImage ) const UINT MAX_BLOCK_BATCH = 64; auto pContext = m_context.Get(); - if ( !pContext ) + if (!pContext) return E_UNEXPECTED; - size_t xblocks = std::max( 1, (m_width + 3) >> 2 ); - size_t yblocks = std::max( 1, (m_height + 3) >> 2 ); + size_t xblocks = std::max(1, (m_width + 3) >> 2); + size_t yblocks = std::max(1, (m_height + 3) >> 2); - UINT num_total_blocks = static_cast( xblocks * yblocks ); + UINT num_total_blocks = static_cast(xblocks * yblocks); UINT num_blocks = num_total_blocks; int start_block_id = 0; while (num_blocks > 0) { - UINT n = std::min( num_blocks, MAX_BLOCK_BATCH ); + UINT n = std::min(num_blocks, MAX_BLOCK_BATCH); UINT uThreadGroupCount = n; { D3D11_MAPPED_SUBRESOURCE mapped; - HRESULT hr = pContext->Map( m_constBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped ); - if ( FAILED(hr) ) + HRESULT hr = pContext->Map(m_constBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); + if (FAILED(hr)) return hr; ConstantsBC6HBC7 param; - param.tex_width = static_cast( srcImage.width ); - param.num_block_x = static_cast( xblocks ); + param.tex_width = static_cast(srcImage.width); + param.num_block_x = static_cast(xblocks); param.format = m_bcformat; param.mode_id = 0; param.start_block_id = start_block_id; param.num_total_blocks = num_total_blocks; param.alpha_weight = m_alphaWeight; - memcpy( mapped.pData, ¶m, sizeof( param ) ); + memcpy(mapped.pData, ¶m, sizeof(param)); - pContext->Unmap( m_constBuffer.Get(), 0 ); + pContext->Unmap(m_constBuffer.Get(), 0); } - if ( isbc7 ) + if (isbc7) { //--- BC7 ----------------------------------------------------------------- ID3D11ShaderResourceView* pSRVs[] = { sourceSRV.Get(), nullptr }; - RunComputeShader( pContext, m_BC7_tryMode456CS.Get(), pSRVs, 2, m_constBuffer.Get(), - m_err1UAV.Get(), std::max( (uThreadGroupCount + 3) / 4, 1) ); + RunComputeShader(pContext, m_BC7_tryMode456CS.Get(), pSRVs, 2, m_constBuffer.Get(), + m_err1UAV.Get(), std::max((uThreadGroupCount + 3) / 4, 1)); - for ( UINT i = 0; i < 3; ++i ) + for (UINT i = 0; i < 3; ++i) { static const UINT modes[] = { 1, 3, 7 }; @@ -467,141 +465,139 @@ HRESULT GPUCompressBC::Compress( const Image& srcImage, const Image& destImage ) // Mode 7: err1 -> err2 { D3D11_MAPPED_SUBRESOURCE mapped; - HRESULT hr = pContext->Map( m_constBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped ); - if ( FAILED(hr) ) + HRESULT hr = pContext->Map(m_constBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); + if (FAILED(hr)) { - ResetContext( pContext ); + ResetContext(pContext); return hr; } ConstantsBC6HBC7 param; - param.tex_width = static_cast( srcImage.width ); - param.num_block_x = static_cast( xblocks ); + param.tex_width = static_cast(srcImage.width); + param.num_block_x = static_cast(xblocks); param.format = m_bcformat; param.mode_id = modes[i]; param.start_block_id = start_block_id; param.num_total_blocks = num_total_blocks; param.alpha_weight = m_alphaWeight; - memcpy( mapped.pData, ¶m, sizeof( param ) ); - pContext->Unmap( m_constBuffer.Get(), 0 ); + memcpy(mapped.pData, ¶m, sizeof(param)); + pContext->Unmap(m_constBuffer.Get(), 0); } pSRVs[1] = (i & 1) ? m_err2SRV.Get() : m_err1SRV.Get(); - RunComputeShader( pContext, m_BC7_tryMode137CS.Get(), pSRVs, 2, m_constBuffer.Get(), - (i & 1) ? m_err1UAV.Get() : m_err2UAV.Get(), uThreadGroupCount ); - } + RunComputeShader(pContext, m_BC7_tryMode137CS.Get(), pSRVs, 2, m_constBuffer.Get(), + (i & 1) ? m_err1UAV.Get() : m_err2UAV.Get(), uThreadGroupCount); + } - if ( !m_skip3Subsets ) + if (!m_skip3Subsets) { // 3 subset modes tend to be used rarely and add significant compression time - for ( UINT i = 0; i < 2; ++i ) + for (UINT i = 0; i < 2; ++i) { static const UINT modes[] = { 0, 2 }; // Mode 0: err2 -> err1 // Mode 2: err1 -> err2 { D3D11_MAPPED_SUBRESOURCE mapped; - HRESULT hr = pContext->Map( m_constBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped ); - if ( FAILED(hr) ) + HRESULT hr = pContext->Map(m_constBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); + if (FAILED(hr)) { - ResetContext( pContext ); + ResetContext(pContext); return hr; } ConstantsBC6HBC7 param; - param.tex_width = static_cast( srcImage.width ); - param.num_block_x = static_cast( xblocks ); + param.tex_width = static_cast(srcImage.width); + param.num_block_x = static_cast(xblocks); param.format = m_bcformat; param.mode_id = modes[i]; param.start_block_id = start_block_id; param.num_total_blocks = num_total_blocks; param.alpha_weight = m_alphaWeight; - memcpy( mapped.pData, ¶m, sizeof( param ) ); - pContext->Unmap( m_constBuffer.Get(), 0 ); + memcpy(mapped.pData, ¶m, sizeof(param)); + pContext->Unmap(m_constBuffer.Get(), 0); } pSRVs[1] = (i & 1) ? m_err1SRV.Get() : m_err2SRV.Get(); - RunComputeShader( pContext, m_BC7_tryMode02CS.Get(), pSRVs, 2, m_constBuffer.Get(), - (i & 1) ? m_err2UAV.Get() : m_err1UAV.Get(), uThreadGroupCount ); + RunComputeShader(pContext, m_BC7_tryMode02CS.Get(), pSRVs, 2, m_constBuffer.Get(), + (i & 1) ? m_err2UAV.Get() : m_err1UAV.Get(), uThreadGroupCount); } } pSRVs[1] = m_err2SRV.Get(); - RunComputeShader( pContext, m_BC7_encodeBlockCS.Get(), pSRVs, 2, m_constBuffer.Get(), - m_outputUAV.Get(), std::max( (uThreadGroupCount + 3) / 4, 1) ); + RunComputeShader(pContext, m_BC7_encodeBlockCS.Get(), pSRVs, 2, m_constBuffer.Get(), + m_outputUAV.Get(), std::max((uThreadGroupCount + 3) / 4, 1)); } else { //--- BC6H ---------------------------------------------------------------- ID3D11ShaderResourceView* pSRVs[] = { sourceSRV.Get(), nullptr }; - RunComputeShader( pContext, m_BC6H_tryModeG10CS.Get(), pSRVs, 2, m_constBuffer.Get(), - m_err1UAV.Get(), std::max( (uThreadGroupCount + 3) / 4, 1) ); + RunComputeShader(pContext, m_BC6H_tryModeG10CS.Get(), pSRVs, 2, m_constBuffer.Get(), + m_err1UAV.Get(), std::max((uThreadGroupCount + 3) / 4, 1)); - for ( UINT i = 0; i < 10; ++i ) + for (UINT i = 0; i < 10; ++i) { { D3D11_MAPPED_SUBRESOURCE mapped; - HRESULT hr = pContext->Map( m_constBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped ); - if ( FAILED(hr) ) + HRESULT hr = pContext->Map(m_constBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); + if (FAILED(hr)) { - ResetContext( pContext ); + ResetContext(pContext); return hr; } ConstantsBC6HBC7 param; - param.tex_width = static_cast( srcImage.width ); - param.num_block_x = static_cast( xblocks ); + param.tex_width = static_cast(srcImage.width); + param.num_block_x = static_cast(xblocks); param.format = m_bcformat; param.mode_id = i; param.start_block_id = start_block_id; param.num_total_blocks = num_total_blocks; - memcpy( mapped.pData, ¶m, sizeof( param ) ); - pContext->Unmap( m_constBuffer.Get(), 0 ); + memcpy(mapped.pData, ¶m, sizeof(param)); + pContext->Unmap(m_constBuffer.Get(), 0); } pSRVs[1] = (i & 1) ? m_err2SRV.Get() : m_err1SRV.Get(); - RunComputeShader( pContext, m_BC6H_tryModeLE10CS.Get(), pSRVs, 2, m_constBuffer.Get(), - (i & 1) ? m_err1UAV.Get() : m_err2UAV.Get(), std::max( (uThreadGroupCount + 1) / 2, 1) ); - } + RunComputeShader(pContext, m_BC6H_tryModeLE10CS.Get(), pSRVs, 2, m_constBuffer.Get(), + (i & 1) ? m_err1UAV.Get() : m_err2UAV.Get(), std::max((uThreadGroupCount + 1) / 2, 1)); + } pSRVs[1] = m_err1SRV.Get(); - RunComputeShader( pContext, m_BC6H_encodeBlockCS.Get(), pSRVs, 2, m_constBuffer.Get(), - m_outputUAV.Get(), std::max( (uThreadGroupCount + 1) / 2, 1) ); + RunComputeShader(pContext, m_BC6H_encodeBlockCS.Get(), pSRVs, 2, m_constBuffer.Get(), + m_outputUAV.Get(), std::max((uThreadGroupCount + 1) / 2, 1)); } start_block_id += n; num_blocks -= n; } - ResetContext( pContext ); + ResetContext(pContext); //--- Copy output texture back to CPU --------------------------------------------- - pContext->CopyResource( m_outputCPU.Get(), m_output.Get() ); + pContext->CopyResource(m_outputCPU.Get(), m_output.Get()); D3D11_MAPPED_SUBRESOURCE mapped; - HRESULT hr = pContext->Map( m_outputCPU.Get(), 0, D3D11_MAP_READ, 0, &mapped ); - if ( SUCCEEDED(hr) ) + HRESULT hr = pContext->Map(m_outputCPU.Get(), 0, D3D11_MAP_READ, 0, &mapped); + if (SUCCEEDED(hr)) { - const uint8_t *pSrc = reinterpret_cast( mapped.pData ); + const uint8_t *pSrc = reinterpret_cast(mapped.pData); uint8_t *pDest = destImage.pixels; - size_t pitch = xblocks * sizeof( BufferBC6HBC7 ); + size_t pitch = xblocks * sizeof(BufferBC6HBC7); - size_t rows = std::max( 1, ( destImage.height + 3 ) >> 2 ); + size_t rows = std::max(1, (destImage.height + 3) >> 2); - for( size_t h = 0; h < rows; ++h ) + for (size_t h = 0; h < rows; ++h) { - memcpy( pDest, pSrc, destImage.rowPitch ); + memcpy(pDest, pSrc, destImage.rowPitch); pSrc += pitch; pDest += destImage.rowPitch; } - pContext->Unmap( m_outputCPU.Get(), 0 ); + pContext->Unmap(m_outputCPU.Get(), 0); } return hr; -} - -}; // namespace \ No newline at end of file +} \ No newline at end of file diff --git a/DirectXTex/DirectXTex.h b/DirectXTex/DirectXTex.h index e2b848b..a4c9c0f 100644 --- a/DirectXTex/DirectXTex.h +++ b/DirectXTex/DirectXTex.h @@ -33,7 +33,7 @@ #include -#define DIRECTX_TEX_VERSION 134 +#define DIRECTX_TEX_VERSION 140 struct IWICImagingFactory; struct IWICMetadataQueryReader; @@ -204,21 +204,21 @@ namespace DirectX // Filtering mode to use for any required image resizing (only needed when loading arrays of differently sized images; defaults to Fant) }; - HRESULT __cdecl GetMetadataFromDDSMemory( _In_reads_bytes_(size) LPCVOID pSource, _In_ size_t size, _In_ DWORD flags, + HRESULT __cdecl GetMetadataFromDDSMemory( _In_reads_bytes_(size) const void* pSource, _In_ size_t size, _In_ DWORD flags, _Out_ TexMetadata& metadata ); - HRESULT __cdecl GetMetadataFromDDSFile( _In_z_ LPCWSTR szFile, _In_ DWORD flags, + HRESULT __cdecl GetMetadataFromDDSFile( _In_z_ const wchar_t* szFile, _In_ DWORD flags, _Out_ TexMetadata& metadata ); - HRESULT __cdecl GetMetadataFromTGAMemory( _In_reads_bytes_(size) LPCVOID pSource, _In_ size_t size, + HRESULT __cdecl GetMetadataFromTGAMemory( _In_reads_bytes_(size) const void* pSource, _In_ size_t size, _Out_ TexMetadata& metadata ); - HRESULT __cdecl GetMetadataFromTGAFile( _In_z_ LPCWSTR szFile, + HRESULT __cdecl GetMetadataFromTGAFile( _In_z_ const wchar_t* szFile, _Out_ TexMetadata& metadata ); - HRESULT __cdecl GetMetadataFromWICMemory( _In_reads_bytes_(size) LPCVOID pSource, _In_ size_t size, _In_ DWORD flags, + HRESULT __cdecl GetMetadataFromWICMemory( _In_reads_bytes_(size) const void* pSource, _In_ size_t size, _In_ DWORD flags, _Out_ TexMetadata& metadata, _In_opt_ std::function getMQR = nullptr); - HRESULT __cdecl GetMetadataFromWICFile( _In_z_ LPCWSTR szFile, _In_ DWORD flags, + HRESULT __cdecl GetMetadataFromWICFile( _In_z_ const wchar_t* szFile, _In_ DWORD flags, _Out_ TexMetadata& metadata, _In_opt_ std::function getMQR = nullptr); @@ -238,13 +238,16 @@ namespace DirectX { public: ScratchImage() - : _nimages(0), _size(0), _image(nullptr), _memory(nullptr) {} + : m_nimages(0), m_size(0), m_image(nullptr), m_memory(nullptr) {} ScratchImage(ScratchImage&& moveFrom) - : _nimages(0), _size(0), _image(nullptr), _memory(nullptr) { *this = std::move(moveFrom); } + : m_nimages(0), m_size(0), m_image(nullptr), m_memory(nullptr) { *this = std::move(moveFrom); } ~ScratchImage() { Release(); } ScratchImage& __cdecl operator= (ScratchImage&& moveFrom); + ScratchImage(const ScratchImage&) = delete; + ScratchImage& operator=(const ScratchImage&) = delete; + HRESULT __cdecl Initialize( _In_ const TexMetadata& mdata, _In_ DWORD flags = CP_FLAGS_NONE ); HRESULT __cdecl Initialize1D( _In_ DXGI_FORMAT fmt, _In_ size_t length, _In_ size_t arraySize, _In_ size_t mipLevels, _In_ DWORD flags = CP_FLAGS_NONE ); @@ -261,27 +264,23 @@ namespace DirectX bool __cdecl OverrideFormat( _In_ DXGI_FORMAT f ); - const TexMetadata& __cdecl GetMetadata() const { return _metadata; } + const TexMetadata& __cdecl GetMetadata() const { return m_metadata; } const Image* __cdecl GetImage(_In_ size_t mip, _In_ size_t item, _In_ size_t slice) const; - const Image* __cdecl GetImages() const { return _image; } - size_t __cdecl GetImageCount() const { return _nimages; } + const Image* __cdecl GetImages() const { return m_image; } + size_t __cdecl GetImageCount() const { return m_nimages; } - uint8_t* __cdecl GetPixels() const { return _memory; } - size_t __cdecl GetPixelsSize() const { return _size; } + uint8_t* __cdecl GetPixels() const { return m_memory; } + size_t __cdecl GetPixelsSize() const { return m_size; } bool __cdecl IsAlphaAllOpaque() const; private: - size_t _nimages; - size_t _size; - TexMetadata _metadata; - Image* _image; - uint8_t* _memory; - - // Hide copy constructor and assignment operator - ScratchImage( const ScratchImage& ); - ScratchImage& operator=( const ScratchImage& ); + size_t m_nimages; + size_t m_size; + TexMetadata m_metadata; + Image* m_image; + uint8_t* m_memory; }; //--------------------------------------------------------------------------------- @@ -289,35 +288,34 @@ namespace DirectX class Blob { public: - Blob() : _buffer(nullptr), _size(0) {} - Blob(Blob&& moveFrom) : _buffer(nullptr), _size(0) { *this = std::move(moveFrom); } + Blob() : m_buffer(nullptr), m_size(0) {} + Blob(Blob&& moveFrom) : m_buffer(nullptr), m_size(0) { *this = std::move(moveFrom); } ~Blob() { Release(); } Blob& __cdecl operator= (Blob&& moveFrom); + Blob(const Blob&) = delete; + Blob& operator=(const Blob&) = delete; + HRESULT __cdecl Initialize( _In_ size_t size ); void __cdecl Release(); - void *__cdecl GetBufferPointer() const { return _buffer; } - size_t __cdecl GetBufferSize() const { return _size; } + void *__cdecl GetBufferPointer() const { return m_buffer; } + size_t __cdecl GetBufferSize() const { return m_size; } private: - void* _buffer; - size_t _size; - - // Hide copy constructor and assignment operator - Blob( const Blob& ); - Blob& operator=( const Blob& ); + void* m_buffer; + size_t m_size; }; //--------------------------------------------------------------------------------- // Image I/O // DDS operations - HRESULT __cdecl LoadFromDDSMemory( _In_reads_bytes_(size) LPCVOID pSource, _In_ size_t size, _In_ DWORD flags, + HRESULT __cdecl LoadFromDDSMemory( _In_reads_bytes_(size) const void* pSource, _In_ size_t size, _In_ DWORD flags, _Out_opt_ TexMetadata* metadata, _Out_ ScratchImage& image ); - HRESULT __cdecl LoadFromDDSFile( _In_z_ LPCWSTR szFile, _In_ DWORD flags, + HRESULT __cdecl LoadFromDDSFile( _In_z_ const wchar_t* szFile, _In_ DWORD flags, _Out_opt_ TexMetadata* metadata, _Out_ ScratchImage& image ); HRESULT __cdecl SaveToDDSMemory( _In_ const Image& image, _In_ DWORD flags, @@ -325,23 +323,23 @@ namespace DirectX HRESULT __cdecl SaveToDDSMemory( _In_reads_(nimages) const Image* images, _In_ size_t nimages, _In_ const TexMetadata& metadata, _In_ DWORD flags, _Out_ Blob& blob ); - HRESULT __cdecl SaveToDDSFile( _In_ const Image& image, _In_ DWORD flags, _In_z_ LPCWSTR szFile ); - HRESULT __cdecl SaveToDDSFile( _In_reads_(nimages) const Image* images, _In_ size_t nimages, _In_ const TexMetadata& metadata, _In_ DWORD flags, _In_z_ LPCWSTR szFile ); + HRESULT __cdecl SaveToDDSFile( _In_ const Image& image, _In_ DWORD flags, _In_z_ const wchar_t* szFile ); + HRESULT __cdecl SaveToDDSFile( _In_reads_(nimages) const Image* images, _In_ size_t nimages, _In_ const TexMetadata& metadata, _In_ DWORD flags, _In_z_ const wchar_t* szFile ); // TGA operations - HRESULT __cdecl LoadFromTGAMemory( _In_reads_bytes_(size) LPCVOID pSource, _In_ size_t size, + HRESULT __cdecl LoadFromTGAMemory( _In_reads_bytes_(size) const void* pSource, _In_ size_t size, _Out_opt_ TexMetadata* metadata, _Out_ ScratchImage& image ); - HRESULT __cdecl LoadFromTGAFile( _In_z_ LPCWSTR szFile, + HRESULT __cdecl LoadFromTGAFile( _In_z_ const wchar_t* szFile, _Out_opt_ TexMetadata* metadata, _Out_ ScratchImage& image ); HRESULT __cdecl SaveToTGAMemory( _In_ const Image& image, _Out_ Blob& blob ); - HRESULT __cdecl SaveToTGAFile( _In_ const Image& image, _In_z_ LPCWSTR szFile ); + HRESULT __cdecl SaveToTGAFile( _In_ const Image& image, _In_z_ const wchar_t* szFile ); // WIC operations - HRESULT __cdecl LoadFromWICMemory( _In_reads_bytes_(size) LPCVOID pSource, _In_ size_t size, _In_ DWORD flags, + HRESULT __cdecl LoadFromWICMemory( _In_reads_bytes_(size) const void* pSource, _In_ size_t size, _In_ DWORD flags, _Out_opt_ TexMetadata* metadata, _Out_ ScratchImage& image, _In_opt_ std::function getMQR = nullptr); - HRESULT __cdecl LoadFromWICFile( _In_z_ LPCWSTR szFile, _In_ DWORD flags, + HRESULT __cdecl LoadFromWICFile( _In_z_ const wchar_t* szFile, _In_ DWORD flags, _Out_opt_ TexMetadata* metadata, _Out_ ScratchImage& image, _In_opt_ std::function getMQR = nullptr); @@ -353,10 +351,10 @@ namespace DirectX _In_opt_ std::function setCustomProps = nullptr ); HRESULT __cdecl SaveToWICFile( _In_ const Image& image, _In_ DWORD flags, _In_ REFGUID guidContainerFormat, - _In_z_ LPCWSTR szFile, _In_opt_ const GUID* targetFormat = nullptr, + _In_z_ const wchar_t* szFile, _In_opt_ const GUID* targetFormat = nullptr, _In_opt_ std::function setCustomProps = nullptr ); HRESULT __cdecl SaveToWICFile( _In_count_(nimages) const Image* images, _In_ size_t nimages, _In_ DWORD flags, _In_ REFGUID guidContainerFormat, - _In_z_ LPCWSTR szFile, _In_opt_ const GUID* targetFormat = nullptr, + _In_z_ const wchar_t* szFile, _In_opt_ const GUID* targetFormat = nullptr, _In_opt_ std::function setCustomProps = nullptr ); //--------------------------------------------------------------------------------- diff --git a/DirectXTex/DirectXTex.inl b/DirectXTex/DirectXTex.inl index 21f59df..5173869 100644 --- a/DirectXTex/DirectXTex.inl +++ b/DirectXTex/DirectXTex.inl @@ -113,7 +113,7 @@ inline HRESULT __cdecl SaveToDDSMemory(const Image& image, DWORD flags, Blob& bl } _Use_decl_annotations_ -inline HRESULT __cdecl SaveToDDSFile(const Image& image, DWORD flags, LPCWSTR szFile) +inline HRESULT __cdecl SaveToDDSFile(const Image& image, DWORD flags, const wchar_t* szFile) { TexMetadata mdata = {}; mdata.width = image.width; diff --git a/DirectXTex/DirectXTexCompress.cpp b/DirectXTex/DirectXTexCompress.cpp index 5b8a583..4db50ca 100644 --- a/DirectXTex/DirectXTexCompress.cpp +++ b/DirectXTex/DirectXTexCompress.cpp @@ -22,554 +22,564 @@ #include "bc.h" +using namespace DirectX; -namespace DirectX +namespace { - -inline static DWORD _GetBCFlags( _In_ DWORD compress ) -{ - static_assert( TEX_COMPRESS_RGB_DITHER == BC_FLAGS_DITHER_RGB, "TEX_COMPRESS_* flags should match BC_FLAGS_*" ); - static_assert( TEX_COMPRESS_A_DITHER == BC_FLAGS_DITHER_A, "TEX_COMPRESS_* flags should match BC_FLAGS_*" ); - static_assert( TEX_COMPRESS_DITHER == (BC_FLAGS_DITHER_RGB | BC_FLAGS_DITHER_A), "TEX_COMPRESS_* flags should match BC_FLAGS_*" ); - static_assert( TEX_COMPRESS_UNIFORM == BC_FLAGS_UNIFORM, "TEX_COMPRESS_* flags should match BC_FLAGS_*" ); - static_assert( TEX_COMPRESS_BC7_USE_3SUBSETS == BC_FLAGS_USE_3SUBSETS, "TEX_COMPRESS_* flags should match BC_FLAGS_*" ); - return ( compress & (BC_FLAGS_DITHER_RGB|BC_FLAGS_DITHER_A|BC_FLAGS_UNIFORM|BC_FLAGS_USE_3SUBSETS) ); -} - -inline static DWORD _GetSRGBFlags( _In_ DWORD compress ) -{ - static_assert( TEX_COMPRESS_SRGB_IN == TEX_FILTER_SRGB_IN, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*" ); - static_assert( TEX_COMPRESS_SRGB_OUT == TEX_FILTER_SRGB_OUT, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*" ); - static_assert( TEX_COMPRESS_SRGB == TEX_FILTER_SRGB, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*" ); - return ( compress & TEX_COMPRESS_SRGB ); -} - -inline static bool _DetermineEncoderSettings( _In_ DXGI_FORMAT format, _Out_ BC_ENCODE& pfEncode, _Out_ size_t& blocksize, _Out_ DWORD& cflags ) -{ - switch(format) + inline DWORD GetBCFlags(_In_ DWORD compress) { - case DXGI_FORMAT_BC1_UNORM: - case DXGI_FORMAT_BC1_UNORM_SRGB: pfEncode = nullptr; blocksize = 8; cflags = 0; break; - case DXGI_FORMAT_BC2_UNORM: - case DXGI_FORMAT_BC2_UNORM_SRGB: pfEncode = D3DXEncodeBC2; blocksize = 16; cflags = 0; break; - case DXGI_FORMAT_BC3_UNORM: - case DXGI_FORMAT_BC3_UNORM_SRGB: pfEncode = D3DXEncodeBC3; blocksize = 16; cflags = 0; break; - case DXGI_FORMAT_BC4_UNORM: pfEncode = D3DXEncodeBC4U; blocksize = 8; cflags = TEX_FILTER_RGB_COPY_RED; break; - case DXGI_FORMAT_BC4_SNORM: pfEncode = D3DXEncodeBC4S; blocksize = 8; cflags = TEX_FILTER_RGB_COPY_RED; break; - case DXGI_FORMAT_BC5_UNORM: pfEncode = D3DXEncodeBC5U; blocksize = 16; cflags = TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN; break; - case DXGI_FORMAT_BC5_SNORM: pfEncode = D3DXEncodeBC5S; blocksize = 16; cflags = TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN; break; - case DXGI_FORMAT_BC6H_UF16: pfEncode = D3DXEncodeBC6HU; blocksize = 16; cflags = 0; break; - case DXGI_FORMAT_BC6H_SF16: pfEncode = D3DXEncodeBC6HS; blocksize = 16; cflags = 0; break; - case DXGI_FORMAT_BC7_UNORM: - case DXGI_FORMAT_BC7_UNORM_SRGB: pfEncode = D3DXEncodeBC7; blocksize = 16; cflags = 0; break; - default: pfEncode = nullptr; blocksize = 0; cflags = 0; return false; + static_assert(TEX_COMPRESS_RGB_DITHER == BC_FLAGS_DITHER_RGB, "TEX_COMPRESS_* flags should match BC_FLAGS_*"); + static_assert(TEX_COMPRESS_A_DITHER == BC_FLAGS_DITHER_A, "TEX_COMPRESS_* flags should match BC_FLAGS_*"); + static_assert(TEX_COMPRESS_DITHER == (BC_FLAGS_DITHER_RGB | BC_FLAGS_DITHER_A), "TEX_COMPRESS_* flags should match BC_FLAGS_*"); + static_assert(TEX_COMPRESS_UNIFORM == BC_FLAGS_UNIFORM, "TEX_COMPRESS_* flags should match BC_FLAGS_*"); + static_assert(TEX_COMPRESS_BC7_USE_3SUBSETS == BC_FLAGS_USE_3SUBSETS, "TEX_COMPRESS_* flags should match BC_FLAGS_*"); + return (compress & (BC_FLAGS_DITHER_RGB | BC_FLAGS_DITHER_A | BC_FLAGS_UNIFORM | BC_FLAGS_USE_3SUBSETS)); } - return true; -} - - -//------------------------------------------------------------------------------------- -static HRESULT _CompressBC( _In_ const Image& image, _In_ const Image& result, _In_ DWORD bcflags, - _In_ DWORD srgb, _In_ float alphaRef ) -{ - if ( !image.pixels || !result.pixels ) - return E_POINTER; - - assert( image.width == result.width ); - assert( image.height == result.height ); - - const DXGI_FORMAT format = image.format; - size_t sbpp = BitsPerPixel( format ); - if ( !sbpp ) - return E_FAIL; - - if ( sbpp < 8 ) + inline DWORD GetSRGBFlags(_In_ DWORD compress) { - // We don't support compressing from monochrome (DXGI_FORMAT_R1_UNORM) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + static_assert(TEX_COMPRESS_SRGB_IN == TEX_FILTER_SRGB_IN, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*"); + static_assert(TEX_COMPRESS_SRGB_OUT == TEX_FILTER_SRGB_OUT, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*"); + static_assert(TEX_COMPRESS_SRGB == TEX_FILTER_SRGB, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*"); + return (compress & TEX_COMPRESS_SRGB); } - // Round to bytes - sbpp = ( sbpp + 7 ) / 8; - - uint8_t *pDest = result.pixels; - - // Determine BC format encoder - BC_ENCODE pfEncode; - size_t blocksize; - DWORD cflags; - if ( !_DetermineEncoderSettings( result.format, pfEncode, blocksize, cflags ) ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); - - __declspec(align(16)) XMVECTOR temp[16]; - const uint8_t *pSrc = image.pixels; - const uint8_t *pEnd = image.pixels + image.slicePitch; - const size_t rowPitch = image.rowPitch; - for( size_t h=0; h < image.height; h += 4 ) + inline bool DetermineEncoderSettings(_In_ DXGI_FORMAT format, _Out_ BC_ENCODE& pfEncode, _Out_ size_t& blocksize, _Out_ DWORD& cflags) { - const uint8_t *sptr = pSrc; - uint8_t* dptr = pDest; - size_t ph = std::min( 4, image.height - h ); - size_t w = 0; - for( size_t count = 0; (count < result.rowPitch) && (w < image.width); count += blocksize, w += 4 ) + switch (format) { - size_t pw = std::min( 4, image.width - w ); - assert( pw > 0 && ph > 0 ); + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: pfEncode = nullptr; blocksize = 8; cflags = 0; break; + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: pfEncode = D3DXEncodeBC2; blocksize = 16; cflags = 0; break; + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: pfEncode = D3DXEncodeBC3; blocksize = 16; cflags = 0; break; + case DXGI_FORMAT_BC4_UNORM: pfEncode = D3DXEncodeBC4U; blocksize = 8; cflags = TEX_FILTER_RGB_COPY_RED; break; + case DXGI_FORMAT_BC4_SNORM: pfEncode = D3DXEncodeBC4S; blocksize = 8; cflags = TEX_FILTER_RGB_COPY_RED; break; + case DXGI_FORMAT_BC5_UNORM: pfEncode = D3DXEncodeBC5U; blocksize = 16; cflags = TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN; break; + case DXGI_FORMAT_BC5_SNORM: pfEncode = D3DXEncodeBC5S; blocksize = 16; cflags = TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN; break; + case DXGI_FORMAT_BC6H_UF16: pfEncode = D3DXEncodeBC6HU; blocksize = 16; cflags = 0; break; + case DXGI_FORMAT_BC6H_SF16: pfEncode = D3DXEncodeBC6HS; blocksize = 16; cflags = 0; break; + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: pfEncode = D3DXEncodeBC7; blocksize = 16; cflags = 0; break; + default: pfEncode = nullptr; blocksize = 0; cflags = 0; return false; + } - ptrdiff_t bytesLeft = pEnd - sptr; - assert( bytesLeft > 0 ); - size_t bytesToRead = std::min( rowPitch, bytesLeft ); - if ( !_LoadScanline( &temp[0], pw, sptr, bytesToRead, format ) ) - return E_FAIL; + return true; + } - if ( ph > 1 ) + + //------------------------------------------------------------------------------------- + HRESULT CompressBC( + const Image& image, + const Image& result, + DWORD bcflags, + DWORD srgb, + float alphaRef) + { + if (!image.pixels || !result.pixels) + return E_POINTER; + + assert(image.width == result.width); + assert(image.height == result.height); + + const DXGI_FORMAT format = image.format; + size_t sbpp = BitsPerPixel(format); + if (!sbpp) + return E_FAIL; + + if (sbpp < 8) + { + // We don't support compressing from monochrome (DXGI_FORMAT_R1_UNORM) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + // Round to bytes + sbpp = (sbpp + 7) / 8; + + uint8_t *pDest = result.pixels; + + // Determine BC format encoder + BC_ENCODE pfEncode; + size_t blocksize; + DWORD cflags; + if (!DetermineEncoderSettings(result.format, pfEncode, blocksize, cflags)) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + + __declspec(align(16)) XMVECTOR temp[16]; + const uint8_t *pSrc = image.pixels; + const uint8_t *pEnd = image.pixels + image.slicePitch; + const size_t rowPitch = image.rowPitch; + for (size_t h = 0; h < image.height; h += 4) + { + const uint8_t *sptr = pSrc; + uint8_t* dptr = pDest; + size_t ph = std::min(4, image.height - h); + size_t w = 0; + for (size_t count = 0; (count < result.rowPitch) && (w < image.width); count += blocksize, w += 4) { - bytesToRead = std::min( rowPitch, bytesLeft - rowPitch ); - if ( !_LoadScanline( &temp[4], pw, sptr + rowPitch, bytesToRead, format ) ) + size_t pw = std::min(4, image.width - w); + assert(pw > 0 && ph > 0); + + ptrdiff_t bytesLeft = pEnd - sptr; + assert(bytesLeft > 0); + size_t bytesToRead = std::min(rowPitch, bytesLeft); + if (!_LoadScanline(&temp[0], pw, sptr, bytesToRead, format)) return E_FAIL; - if ( ph > 2 ) + if (ph > 1) { - bytesToRead = std::min( rowPitch, bytesLeft - rowPitch * 2 ); - if ( !_LoadScanline( &temp[8], pw, sptr + rowPitch*2, bytesToRead, format ) ) + bytesToRead = std::min(rowPitch, bytesLeft - rowPitch); + if (!_LoadScanline(&temp[4], pw, sptr + rowPitch, bytesToRead, format)) return E_FAIL; - if ( ph > 3 ) + if (ph > 2) { - bytesToRead = std::min( rowPitch, bytesLeft - rowPitch * 3 ); - if ( !_LoadScanline( &temp[12], pw, sptr + rowPitch*3, bytesToRead, format ) ) + bytesToRead = std::min(rowPitch, bytesLeft - rowPitch * 2); + if (!_LoadScanline(&temp[8], pw, sptr + rowPitch * 2, bytesToRead, format)) return E_FAIL; + + if (ph > 3) + { + bytesToRead = std::min(rowPitch, bytesLeft - rowPitch * 3); + if (!_LoadScanline(&temp[12], pw, sptr + rowPitch * 3, bytesToRead, format)) + return E_FAIL; + } + } + } + + if (pw != 4 || ph != 4) + { + // Replicate pixels for partial block + static const size_t uSrc[] = { 0, 0, 0, 1 }; + + if (pw < 4) + { + for (size_t t = 0; t < ph && t < 4; ++t) + { + for (size_t s = pw; s < 4; ++s) + { +#pragma prefast(suppress: 26000, "PREFAST false positive") + temp[(t << 2) | s] = temp[(t << 2) | uSrc[s]]; + } + } + } + + if (ph < 4) + { + for (size_t t = ph; t < 4; ++t) + { + for (size_t s = 0; s < 4; ++s) + { +#pragma prefast(suppress: 26000, "PREFAST false positive") + temp[(t << 2) | s] = temp[(uSrc[t] << 2) | s]; + } + } + } + } + + _ConvertScanline(temp, 16, result.format, format, cflags | srgb); + + if (pfEncode) + pfEncode(dptr, temp, bcflags); + else + D3DXEncodeBC1(dptr, temp, alphaRef, bcflags); + + sptr += sbpp * 4; + dptr += blocksize; + } + + pSrc += rowPitch * 4; + pDest += result.rowPitch; + } + + return S_OK; + } + + + //------------------------------------------------------------------------------------- +#ifdef _OPENMP + HRESULT CompressBC_Parallel( + const Image& image, + const Image& result, + DWORD bcflags, + DWORD srgb, + float alphaRef) + { + if (!image.pixels || !result.pixels) + return E_POINTER; + + assert(image.width == result.width); + assert(image.height == result.height); + + const DXGI_FORMAT format = image.format; + size_t sbpp = BitsPerPixel(format); + if (!sbpp) + return E_FAIL; + + if (sbpp < 8) + { + // We don't support compressing from monochrome (DXGI_FORMAT_R1_UNORM) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + // Round to bytes + sbpp = (sbpp + 7) / 8; + + const uint8_t *pEnd = image.pixels + image.slicePitch; + + // Determine BC format encoder + BC_ENCODE pfEncode; + size_t blocksize; + DWORD cflags; + if (!DetermineEncoderSettings(result.format, pfEncode, blocksize, cflags)) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + + // Refactored version of loop to support parallel independance + const size_t nBlocks = std::max(1, (image.width + 3) / 4) * std::max(1, (image.height + 3) / 4); + + bool fail = false; + +#pragma omp parallel for + for (int nb = 0; nb < static_cast(nBlocks); ++nb) + { + int nbWidth = std::max(1, int((image.width + 3) / 4)); + + int y = nb / nbWidth; + int x = (nb - (y*nbWidth)) * 4; + y *= 4; + + assert((x >= 0) && (x < int(image.width))); + assert((y >= 0) && (y < int(image.height))); + + size_t rowPitch = image.rowPitch; + const uint8_t *pSrc = image.pixels + (y*rowPitch) + (x*sbpp); + + uint8_t *pDest = result.pixels + (nb*blocksize); + + size_t ph = std::min(4, image.height - y); + size_t pw = std::min(4, image.width - x); + assert(pw > 0 && ph > 0); + + ptrdiff_t bytesLeft = pEnd - pSrc; + assert(bytesLeft > 0); + size_t bytesToRead = std::min(rowPitch, bytesLeft); + + __declspec(align(16)) XMVECTOR temp[16]; + if (!_LoadScanline(&temp[0], pw, pSrc, bytesToRead, format)) + fail = true; + + if (ph > 1) + { + bytesToRead = std::min(rowPitch, bytesLeft - rowPitch); + if (!_LoadScanline(&temp[4], pw, pSrc + rowPitch, bytesToRead, format)) + fail = true; + + if (ph > 2) + { + bytesToRead = std::min(rowPitch, bytesLeft - rowPitch * 2); + if (!_LoadScanline(&temp[8], pw, pSrc + rowPitch * 2, bytesToRead, format)) + fail = true; + + if (ph > 3) + { + bytesToRead = std::min(rowPitch, bytesLeft - rowPitch * 3); + if (!_LoadScanline(&temp[12], pw, pSrc + rowPitch * 3, bytesToRead, format)) + fail = true; } } } - if ( pw != 4 || ph != 4 ) + if (pw != 4 || ph != 4) { // Replicate pixels for partial block static const size_t uSrc[] = { 0, 0, 0, 1 }; - if ( pw < 4 ) + if (pw < 4) { - for( size_t t = 0; t < ph && t < 4; ++t ) + for (size_t t = 0; t < ph && t < 4; ++t) { - for( size_t s = pw; s < 4; ++s ) + for (size_t s = pw; s < 4; ++s) { -#pragma prefast(suppress: 26000, "PREFAST false positive") - temp[ (t << 2) | s ] = temp[ (t << 2) | uSrc[s] ]; + temp[(t << 2) | s] = temp[(t << 2) | uSrc[s]]; } } } - if ( ph < 4 ) + if (ph < 4) { - for( size_t t = ph; t < 4; ++t ) + for (size_t t = ph; t < 4; ++t) { - for( size_t s = 0; s < 4; ++s ) + for (size_t s = 0; s < 4; ++s) { -#pragma prefast(suppress: 26000, "PREFAST false positive") - temp[ (t << 2) | s ] = temp[ (uSrc[t] << 2) | s ]; + temp[(t << 2) | s] = temp[(uSrc[t] << 2) | s]; } } } } - _ConvertScanline( temp, 16, result.format, format, cflags | srgb ); - - if ( pfEncode ) - pfEncode( dptr, temp, bcflags ); + _ConvertScanline(temp, 16, result.format, format, cflags | srgb); + + if (pfEncode) + pfEncode(pDest, temp, bcflags); else - D3DXEncodeBC1( dptr, temp, alphaRef, bcflags ); - - sptr += sbpp*4; - dptr += blocksize; + D3DXEncodeBC1(pDest, temp, alphaRef, bcflags); } - pSrc += rowPitch*4; - pDest += result.rowPitch; + return (fail) ? E_FAIL : S_OK; } - - return S_OK; -} - - -//------------------------------------------------------------------------------------- -#ifdef _OPENMP -static HRESULT _CompressBC_Parallel( _In_ const Image& image, _In_ const Image& result, _In_ DWORD bcflags, - _In_ DWORD srgb, _In_ float alphaRef ) -{ - if ( !image.pixels || !result.pixels ) - return E_POINTER; - - assert( image.width == result.width ); - assert( image.height == result.height ); - - const DXGI_FORMAT format = image.format; - size_t sbpp = BitsPerPixel( format ); - if ( !sbpp ) - return E_FAIL; - - if ( sbpp < 8 ) - { - // We don't support compressing from monochrome (DXGI_FORMAT_R1_UNORM) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); - } - - // Round to bytes - sbpp = ( sbpp + 7 ) / 8; - - const uint8_t *pEnd = image.pixels + image.slicePitch; - - // Determine BC format encoder - BC_ENCODE pfEncode; - size_t blocksize; - DWORD cflags; - if ( !_DetermineEncoderSettings( result.format, pfEncode, blocksize, cflags ) ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); - - // Refactored version of loop to support parallel independance - const size_t nBlocks = std::max(1, (image.width + 3) / 4 ) * std::max(1, (image.height + 3) / 4 ); - - bool fail = false; - -#pragma omp parallel for - for( int nb=0; nb < static_cast( nBlocks ); ++nb ) - { - int nbWidth = std::max(1, int( (image.width + 3) / 4 ) ); - - int y = nb / nbWidth; - int x = ( nb - (y*nbWidth) ) * 4; - y *= 4; - - assert( (x >= 0) && (x < int(image.width)) ); - assert( (y >= 0) && (y < int(image.height)) ); - - size_t rowPitch = image.rowPitch; - const uint8_t *pSrc = image.pixels + (y*rowPitch) + (x*sbpp); - - uint8_t *pDest = result.pixels + (nb*blocksize); - - size_t ph = std::min( 4, image.height - y ); - size_t pw = std::min( 4, image.width - x ); - assert( pw > 0 && ph > 0 ); - - ptrdiff_t bytesLeft = pEnd - pSrc; - assert( bytesLeft > 0 ); - size_t bytesToRead = std::min( rowPitch, bytesLeft ); - - __declspec(align(16)) XMVECTOR temp[16]; - if ( !_LoadScanline( &temp[0], pw, pSrc, bytesToRead, format ) ) - fail = true; - - if ( ph > 1 ) - { - bytesToRead = std::min( rowPitch, bytesLeft - rowPitch ); - if ( !_LoadScanline( &temp[4], pw, pSrc + rowPitch, bytesToRead, format ) ) - fail = true; - - if ( ph > 2 ) - { - bytesToRead = std::min( rowPitch, bytesLeft - rowPitch * 2 ); - if ( !_LoadScanline( &temp[8], pw, pSrc + rowPitch*2, bytesToRead, format ) ) - fail = true; - - if ( ph > 3 ) - { - bytesToRead = std::min( rowPitch, bytesLeft - rowPitch * 3 ); - if ( !_LoadScanline( &temp[12], pw, pSrc + rowPitch*3, bytesToRead, format ) ) - fail = true; - } - } - } - - if ( pw != 4 || ph != 4 ) - { - // Replicate pixels for partial block - static const size_t uSrc[] = { 0, 0, 0, 1 }; - - if ( pw < 4 ) - { - for( size_t t = 0; t < ph && t < 4; ++t ) - { - for( size_t s = pw; s < 4; ++s ) - { - temp[ (t << 2) | s ] = temp[ (t << 2) | uSrc[s] ]; - } - } - } - - if ( ph < 4 ) - { - for( size_t t = ph; t < 4; ++t ) - { - for( size_t s = 0; s < 4; ++s ) - { - temp[ (t << 2) | s ] = temp[ (uSrc[t] << 2) | s ]; - } - } - } - } - - _ConvertScanline( temp, 16, result.format, format, cflags | srgb ); - - if ( pfEncode ) - pfEncode( pDest, temp, bcflags ); - else - D3DXEncodeBC1( pDest, temp, alphaRef, bcflags ); - } - - return (fail) ? E_FAIL : S_OK; -} - #endif // _OPENMP -//------------------------------------------------------------------------------------- -static DXGI_FORMAT _DefaultDecompress( _In_ DXGI_FORMAT format ) -{ - switch( format ) + //------------------------------------------------------------------------------------- + DXGI_FORMAT DefaultDecompress(_In_ DXGI_FORMAT format) { - case DXGI_FORMAT_BC1_TYPELESS: - case DXGI_FORMAT_BC1_UNORM: - case DXGI_FORMAT_BC2_TYPELESS: - case DXGI_FORMAT_BC2_UNORM: - case DXGI_FORMAT_BC3_TYPELESS: - case DXGI_FORMAT_BC3_UNORM: - case DXGI_FORMAT_BC7_TYPELESS: - case DXGI_FORMAT_BC7_UNORM: - return DXGI_FORMAT_R8G8B8A8_UNORM; - - case DXGI_FORMAT_BC1_UNORM_SRGB: - case DXGI_FORMAT_BC2_UNORM_SRGB: - case DXGI_FORMAT_BC3_UNORM_SRGB: - case DXGI_FORMAT_BC7_UNORM_SRGB: - return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; - - case DXGI_FORMAT_BC4_TYPELESS: - case DXGI_FORMAT_BC4_UNORM: - return DXGI_FORMAT_R8_UNORM; - - case DXGI_FORMAT_BC4_SNORM: - return DXGI_FORMAT_R8_SNORM; - - case DXGI_FORMAT_BC5_TYPELESS: - case DXGI_FORMAT_BC5_UNORM: - return DXGI_FORMAT_R8G8_UNORM; - - case DXGI_FORMAT_BC5_SNORM: - return DXGI_FORMAT_R8G8_SNORM; - - case DXGI_FORMAT_BC6H_TYPELESS: - case DXGI_FORMAT_BC6H_UF16: - case DXGI_FORMAT_BC6H_SF16: - // We could use DXGI_FORMAT_R32G32B32_FLOAT here since BC6H is always Alpha 1.0, - // but this format is more supported by viewers - return DXGI_FORMAT_R32G32B32A32_FLOAT; - - default: - return DXGI_FORMAT_UNKNOWN; - } -} - - -//------------------------------------------------------------------------------------- -static HRESULT _DecompressBC( _In_ const Image& cImage, _In_ const Image& result ) -{ - if ( !cImage.pixels || !result.pixels ) - return E_POINTER; - - assert( cImage.width == result.width ); - assert( cImage.height == result.height ); - - const DXGI_FORMAT format = result.format; - size_t dbpp = BitsPerPixel( format ); - if ( !dbpp ) - return E_FAIL; - - if ( dbpp < 8 ) - { - // We don't support decompressing to monochrome (DXGI_FORMAT_R1_UNORM) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); - } - - // Round to bytes - dbpp = ( dbpp + 7 ) / 8; - - uint8_t *pDest = result.pixels; - if ( !pDest ) - return E_POINTER; - - // Promote "typeless" BC formats - DXGI_FORMAT cformat; - switch( cImage.format ) - { - case DXGI_FORMAT_BC1_TYPELESS: cformat = DXGI_FORMAT_BC1_UNORM; break; - case DXGI_FORMAT_BC2_TYPELESS: cformat = DXGI_FORMAT_BC2_UNORM; break; - case DXGI_FORMAT_BC3_TYPELESS: cformat = DXGI_FORMAT_BC3_UNORM; break; - case DXGI_FORMAT_BC4_TYPELESS: cformat = DXGI_FORMAT_BC4_UNORM; break; - case DXGI_FORMAT_BC5_TYPELESS: cformat = DXGI_FORMAT_BC5_UNORM; break; - case DXGI_FORMAT_BC6H_TYPELESS: cformat = DXGI_FORMAT_BC6H_UF16; break; - case DXGI_FORMAT_BC7_TYPELESS: cformat = DXGI_FORMAT_BC7_UNORM; break; - default: cformat = cImage.format; break; - } - - // Determine BC format decoder - BC_DECODE pfDecode; - size_t sbpp; - switch(cformat) - { - case DXGI_FORMAT_BC1_UNORM: - case DXGI_FORMAT_BC1_UNORM_SRGB: pfDecode = D3DXDecodeBC1; sbpp = 8; break; - case DXGI_FORMAT_BC2_UNORM: - case DXGI_FORMAT_BC2_UNORM_SRGB: pfDecode = D3DXDecodeBC2; sbpp = 16; break; - case DXGI_FORMAT_BC3_UNORM: - case DXGI_FORMAT_BC3_UNORM_SRGB: pfDecode = D3DXDecodeBC3; sbpp = 16; break; - case DXGI_FORMAT_BC4_UNORM: pfDecode = D3DXDecodeBC4U; sbpp = 8; break; - case DXGI_FORMAT_BC4_SNORM: pfDecode = D3DXDecodeBC4S; sbpp = 8; break; - case DXGI_FORMAT_BC5_UNORM: pfDecode = D3DXDecodeBC5U; sbpp = 16; break; - case DXGI_FORMAT_BC5_SNORM: pfDecode = D3DXDecodeBC5S; sbpp = 16; break; - case DXGI_FORMAT_BC6H_UF16: pfDecode = D3DXDecodeBC6HU; sbpp = 16; break; - case DXGI_FORMAT_BC6H_SF16: pfDecode = D3DXDecodeBC6HS; sbpp = 16; break; - case DXGI_FORMAT_BC7_UNORM: - case DXGI_FORMAT_BC7_UNORM_SRGB: pfDecode = D3DXDecodeBC7; sbpp = 16; break; - default: - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); - } - - __declspec(align(16)) XMVECTOR temp[16]; - const uint8_t *pSrc = cImage.pixels; - const size_t rowPitch = result.rowPitch; - for( size_t h=0; h < cImage.height; h += 4 ) - { - const uint8_t *sptr = pSrc; - uint8_t* dptr = pDest; - size_t ph = std::min( 4, cImage.height - h ); - size_t w = 0; - for( size_t count = 0; (count < cImage.rowPitch) && (w < cImage.width); count += sbpp, w += 4 ) + switch (format) { - pfDecode( temp, sptr ); - _ConvertScanline( temp, 16, format, cformat, 0 ); + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM: + return DXGI_FORMAT_R8G8B8A8_UNORM; - size_t pw = std::min( 4, cImage.width - w ); - assert( pw > 0 && ph > 0 ); + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_BC7_UNORM_SRGB: + return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; - if ( !_StoreScanline( dptr, rowPitch, format, &temp[0], pw ) ) - return E_FAIL; + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + return DXGI_FORMAT_R8_UNORM; - if ( ph > 1 ) - { - if ( !_StoreScanline( dptr + rowPitch, rowPitch, format, &temp[4], pw ) ) - return E_FAIL; + case DXGI_FORMAT_BC4_SNORM: + return DXGI_FORMAT_R8_SNORM; - if ( ph > 2 ) - { - if ( !_StoreScanline( dptr + rowPitch*2, rowPitch, format, &temp[8], pw ) ) - return E_FAIL; + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + return DXGI_FORMAT_R8G8_UNORM; - if ( ph > 3 ) - { - if ( !_StoreScanline( dptr + rowPitch*3, rowPitch, format, &temp[12], pw ) ) - return E_FAIL; - } - } - } + case DXGI_FORMAT_BC5_SNORM: + return DXGI_FORMAT_R8G8_SNORM; - sptr += sbpp; - dptr += dbpp*4; + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: + // We could use DXGI_FORMAT_R32G32B32_FLOAT here since BC6H is always Alpha 1.0, + // but this format is more supported by viewers + return DXGI_FORMAT_R32G32B32A32_FLOAT; + + default: + return DXGI_FORMAT_UNKNOWN; + } + } + + + //------------------------------------------------------------------------------------- + HRESULT DecompressBC(_In_ const Image& cImage, _In_ const Image& result) + { + if (!cImage.pixels || !result.pixels) + return E_POINTER; + + assert(cImage.width == result.width); + assert(cImage.height == result.height); + + const DXGI_FORMAT format = result.format; + size_t dbpp = BitsPerPixel(format); + if (!dbpp) + return E_FAIL; + + if (dbpp < 8) + { + // We don't support decompressing to monochrome (DXGI_FORMAT_R1_UNORM) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } - pSrc += cImage.rowPitch; - pDest += rowPitch*4; - } + // Round to bytes + dbpp = (dbpp + 7) / 8; - return S_OK; + uint8_t *pDest = result.pixels; + if (!pDest) + return E_POINTER; + + // Promote "typeless" BC formats + DXGI_FORMAT cformat; + switch (cImage.format) + { + case DXGI_FORMAT_BC1_TYPELESS: cformat = DXGI_FORMAT_BC1_UNORM; break; + case DXGI_FORMAT_BC2_TYPELESS: cformat = DXGI_FORMAT_BC2_UNORM; break; + case DXGI_FORMAT_BC3_TYPELESS: cformat = DXGI_FORMAT_BC3_UNORM; break; + case DXGI_FORMAT_BC4_TYPELESS: cformat = DXGI_FORMAT_BC4_UNORM; break; + case DXGI_FORMAT_BC5_TYPELESS: cformat = DXGI_FORMAT_BC5_UNORM; break; + case DXGI_FORMAT_BC6H_TYPELESS: cformat = DXGI_FORMAT_BC6H_UF16; break; + case DXGI_FORMAT_BC7_TYPELESS: cformat = DXGI_FORMAT_BC7_UNORM; break; + default: cformat = cImage.format; break; + } + + // Determine BC format decoder + BC_DECODE pfDecode; + size_t sbpp; + switch (cformat) + { + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: pfDecode = D3DXDecodeBC1; sbpp = 8; break; + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: pfDecode = D3DXDecodeBC2; sbpp = 16; break; + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: pfDecode = D3DXDecodeBC3; sbpp = 16; break; + case DXGI_FORMAT_BC4_UNORM: pfDecode = D3DXDecodeBC4U; sbpp = 8; break; + case DXGI_FORMAT_BC4_SNORM: pfDecode = D3DXDecodeBC4S; sbpp = 8; break; + case DXGI_FORMAT_BC5_UNORM: pfDecode = D3DXDecodeBC5U; sbpp = 16; break; + case DXGI_FORMAT_BC5_SNORM: pfDecode = D3DXDecodeBC5S; sbpp = 16; break; + case DXGI_FORMAT_BC6H_UF16: pfDecode = D3DXDecodeBC6HU; sbpp = 16; break; + case DXGI_FORMAT_BC6H_SF16: pfDecode = D3DXDecodeBC6HS; sbpp = 16; break; + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: pfDecode = D3DXDecodeBC7; sbpp = 16; break; + default: + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + __declspec(align(16)) XMVECTOR temp[16]; + const uint8_t *pSrc = cImage.pixels; + const size_t rowPitch = result.rowPitch; + for (size_t h = 0; h < cImage.height; h += 4) + { + const uint8_t *sptr = pSrc; + uint8_t* dptr = pDest; + size_t ph = std::min(4, cImage.height - h); + size_t w = 0; + for (size_t count = 0; (count < cImage.rowPitch) && (w < cImage.width); count += sbpp, w += 4) + { + pfDecode(temp, sptr); + _ConvertScanline(temp, 16, format, cformat, 0); + + size_t pw = std::min(4, cImage.width - w); + assert(pw > 0 && ph > 0); + + if (!_StoreScanline(dptr, rowPitch, format, &temp[0], pw)) + return E_FAIL; + + if (ph > 1) + { + if (!_StoreScanline(dptr + rowPitch, rowPitch, format, &temp[4], pw)) + return E_FAIL; + + if (ph > 2) + { + if (!_StoreScanline(dptr + rowPitch * 2, rowPitch, format, &temp[8], pw)) + return E_FAIL; + + if (ph > 3) + { + if (!_StoreScanline(dptr + rowPitch * 3, rowPitch, format, &temp[12], pw)) + return E_FAIL; + } + } + } + + sptr += sbpp; + dptr += dbpp * 4; + } + + pSrc += cImage.rowPitch; + pDest += rowPitch * 4; + } + + return S_OK; + } } - //------------------------------------------------------------------------------------- -bool _IsAlphaAllOpaqueBC( _In_ const Image& cImage ) +namespace DirectX { - if ( !cImage.pixels ) - return false; - - // Promote "typeless" BC formats - DXGI_FORMAT cformat; - switch( cImage.format ) + bool _IsAlphaAllOpaqueBC(_In_ const Image& cImage) { - case DXGI_FORMAT_BC1_TYPELESS: cformat = DXGI_FORMAT_BC1_UNORM; break; - case DXGI_FORMAT_BC2_TYPELESS: cformat = DXGI_FORMAT_BC2_UNORM; break; - case DXGI_FORMAT_BC3_TYPELESS: cformat = DXGI_FORMAT_BC3_UNORM; break; - case DXGI_FORMAT_BC7_TYPELESS: cformat = DXGI_FORMAT_BC7_UNORM; break; - default: cformat = cImage.format; break; - } + if (!cImage.pixels) + return false; - // Determine BC format decoder - BC_DECODE pfDecode; - size_t sbpp; - switch(cformat) - { - case DXGI_FORMAT_BC1_UNORM: - case DXGI_FORMAT_BC1_UNORM_SRGB: pfDecode = D3DXDecodeBC1; sbpp = 8; break; - case DXGI_FORMAT_BC2_UNORM: - case DXGI_FORMAT_BC2_UNORM_SRGB: pfDecode = D3DXDecodeBC2; sbpp = 16; break; - case DXGI_FORMAT_BC3_UNORM: - case DXGI_FORMAT_BC3_UNORM_SRGB: pfDecode = D3DXDecodeBC3; sbpp = 16; break; - case DXGI_FORMAT_BC7_UNORM: - case DXGI_FORMAT_BC7_UNORM_SRGB: pfDecode = D3DXDecodeBC7; sbpp = 16; break; - default: - // BC4, BC5, and BC6 don't have alpha channels - return false; - } - - // Scan blocks for non-opaque alpha - static const XMVECTORF32 threshold = { 0.99f, 0.99f, 0.99f, 0.99f }; - - __declspec(align(16)) XMVECTOR temp[16]; - const uint8_t *pPixels = cImage.pixels; - for( size_t h = 0; h < cImage.height; h += 4 ) - { - const uint8_t *ptr = pPixels; - size_t ph = std::min( 4, cImage.height - h ); - size_t w = 0; - for( size_t count = 0; (count < cImage.rowPitch) && (w < cImage.width); count += sbpp, w += 4 ) + // Promote "typeless" BC formats + DXGI_FORMAT cformat; + switch (cImage.format) { - pfDecode( temp, ptr ); + case DXGI_FORMAT_BC1_TYPELESS: cformat = DXGI_FORMAT_BC1_UNORM; break; + case DXGI_FORMAT_BC2_TYPELESS: cformat = DXGI_FORMAT_BC2_UNORM; break; + case DXGI_FORMAT_BC3_TYPELESS: cformat = DXGI_FORMAT_BC3_UNORM; break; + case DXGI_FORMAT_BC7_TYPELESS: cformat = DXGI_FORMAT_BC7_UNORM; break; + default: cformat = cImage.format; break; + } - size_t pw = std::min( 4, cImage.width - w ); - assert( pw > 0 && ph > 0 ); + // Determine BC format decoder + BC_DECODE pfDecode; + size_t sbpp; + switch (cformat) + { + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: pfDecode = D3DXDecodeBC1; sbpp = 8; break; + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: pfDecode = D3DXDecodeBC2; sbpp = 16; break; + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: pfDecode = D3DXDecodeBC3; sbpp = 16; break; + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: pfDecode = D3DXDecodeBC7; sbpp = 16; break; + default: + // BC4, BC5, and BC6 don't have alpha channels + return false; + } - if ( pw == 4 && ph == 4 ) + // Scan blocks for non-opaque alpha + static const XMVECTORF32 threshold = { 0.99f, 0.99f, 0.99f, 0.99f }; + + __declspec(align(16)) XMVECTOR temp[16]; + const uint8_t *pPixels = cImage.pixels; + for (size_t h = 0; h < cImage.height; h += 4) + { + const uint8_t *ptr = pPixels; + size_t ph = std::min(4, cImage.height - h); + size_t w = 0; + for (size_t count = 0; (count < cImage.rowPitch) && (w < cImage.width); count += sbpp, w += 4) { - // Full blocks - for( size_t j = 0; j < 16; ++j ) + pfDecode(temp, ptr); + + size_t pw = std::min(4, cImage.width - w); + assert(pw > 0 && ph > 0); + + if (pw == 4 && ph == 4) { - XMVECTOR alpha = XMVectorSplatW( temp[j] ); - if ( XMVector4Less( alpha, threshold ) ) - return false; - } - } - else - { - // Handle partial blocks - for( size_t y = 0; y < ph; ++y ) - { - for( size_t x = 0; x < pw; ++x ) + // Full blocks + for (size_t j = 0; j < 16; ++j) { - XMVECTOR alpha = XMVectorSplatW( temp[ y * 4 + x ] ); - if ( XMVector4Less( alpha, threshold ) ) + XMVECTOR alpha = XMVectorSplatW(temp[j]); + if (XMVector4Less(alpha, threshold)) return false; } } + else + { + // Handle partial blocks + for (size_t y = 0; y < ph; ++y) + { + for (size_t x = 0; x < pw; ++x) + { + XMVECTOR alpha = XMVectorSplatW(temp[y * 4 + x]); + if (XMVector4Less(alpha, threshold)) + return false; + } + } + } + + ptr += sbpp; } - ptr += sbpp; + pPixels += cImage.rowPitch; } - pPixels += cImage.rowPitch; + return true; } - - return true; -} +}; //===================================================================================== @@ -580,22 +590,27 @@ bool _IsAlphaAllOpaqueBC( _In_ const Image& cImage ) // Compression //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT Compress( const Image& srcImage, DXGI_FORMAT format, DWORD compress, float alphaRef, ScratchImage& image ) +HRESULT DirectX::Compress( + const Image& srcImage, + DXGI_FORMAT format, + DWORD compress, + float alphaRef, + ScratchImage& image) { - if ( IsCompressed(srcImage.format) || !IsCompressed(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 ); + 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) ) + HRESULT hr = image.Initialize2D(format, srcImage.width, srcImage.height, 1, 1); + if (FAILED(hr)) return hr; - const Image *img = image.GetImage( 0, 0, 0 ); - if ( !img ) + const Image *img = image.GetImage(0, 0, 0); + if (!img) { image.Release(); return E_POINTER; @@ -607,76 +622,82 @@ HRESULT Compress( const Image& srcImage, DXGI_FORMAT format, DWORD compress, flo #ifndef _OPENMP return E_NOTIMPL; #else - hr = _CompressBC_Parallel( srcImage, *img, _GetBCFlags( compress ), _GetSRGBFlags( compress ), alphaRef ); + hr = CompressBC_Parallel(srcImage, *img, GetBCFlags(compress), GetSRGBFlags(compress), alphaRef); #endif // _OPENMP } else { - hr = _CompressBC( srcImage, *img, _GetBCFlags( compress ), _GetSRGBFlags( compress ), alphaRef ); + hr = CompressBC(srcImage, *img, GetBCFlags(compress), GetSRGBFlags(compress), alphaRef); } - if ( FAILED(hr) ) + if (FAILED(hr)) image.Release(); return hr; } _Use_decl_annotations_ -HRESULT Compress( const Image* srcImages, size_t nimages, const TexMetadata& metadata, - DXGI_FORMAT format, DWORD compress, float alphaRef, ScratchImage& cImages ) +HRESULT DirectX::Compress( + const Image* srcImages, + size_t nimages, + const TexMetadata& metadata, + DXGI_FORMAT format, + DWORD compress, + float alphaRef, + ScratchImage& cImages) { - if ( !srcImages || !nimages ) + if (!srcImages || !nimages) return E_INVALIDARG; - if ( IsCompressed(metadata.format) || !IsCompressed(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 ); + if (IsTypeless(format) + || IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format)) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); cImages.Release(); TexMetadata mdata2 = metadata; mdata2.format = format; - HRESULT hr = cImages.Initialize( mdata2 ); - if ( FAILED(hr) ) + HRESULT hr = cImages.Initialize(mdata2); + if (FAILED(hr)) return hr; - if ( nimages != cImages.GetImageCount() ) + if (nimages != cImages.GetImageCount()) { cImages.Release(); return E_FAIL; } const Image* dest = cImages.GetImages(); - if ( !dest ) + if (!dest) { cImages.Release(); return E_POINTER; } - for( size_t index=0; index < nimages; ++index ) + for (size_t index = 0; index < nimages; ++index) { - assert( dest[ index ].format == format ); + assert(dest[index].format == format); - const Image& src = srcImages[ index ]; + const Image& src = srcImages[index]; - if ( src.width != dest[ index ].width || src.height != dest[ index ].height ) + if (src.width != dest[index].width || src.height != dest[index].height) { cImages.Release(); return E_FAIL; } - if ( (compress & TEX_COMPRESS_PARALLEL) ) + if ((compress & TEX_COMPRESS_PARALLEL)) { #ifndef _OPENMP return E_NOTIMPL; #else - if ( compress & TEX_COMPRESS_PARALLEL ) + if (compress & TEX_COMPRESS_PARALLEL) { - hr = _CompressBC_Parallel( src, dest[ index ], _GetBCFlags( compress ), _GetSRGBFlags( compress ), alphaRef ); - if ( FAILED(hr) ) + hr = CompressBC_Parallel(src, dest[index], GetBCFlags(compress), GetSRGBFlags(compress), alphaRef); + if (FAILED(hr)) { cImages.Release(); return hr; @@ -686,8 +707,8 @@ HRESULT Compress( const Image* srcImages, size_t nimages, const TexMetadata& met } else { - hr = _CompressBC( src, dest[ index ], _GetBCFlags( compress ), _GetSRGBFlags( compress ), alphaRef ); - if ( FAILED(hr) ) + hr = CompressBC(src, dest[index], GetBCFlags(compress), GetSRGBFlags(compress), alphaRef); + if (FAILED(hr)) { cImages.Release(); return hr; @@ -703,16 +724,19 @@ HRESULT Compress( const Image* srcImages, size_t nimages, const TexMetadata& met // Decompression //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT Decompress( const Image& cImage, DXGI_FORMAT format, ScratchImage& image ) +HRESULT DirectX::Decompress( + const Image& cImage, + DXGI_FORMAT format, + ScratchImage& image) { - if ( !IsCompressed(cImage.format) || IsCompressed(format) ) + if (!IsCompressed(cImage.format) || IsCompressed(format)) return E_INVALIDARG; - if ( format == DXGI_FORMAT_UNKNOWN ) + if (format == DXGI_FORMAT_UNKNOWN) { // Pick a default decompressed format based on BC input format - format = _DefaultDecompress( cImage.format ); - if ( format == DXGI_FORMAT_UNKNOWN ) + format = DefaultDecompress(cImage.format); + if (format == DXGI_FORMAT_UNKNOWN) { // Input is not a compressed format return E_INVALIDARG; @@ -720,48 +744,52 @@ HRESULT Decompress( const Image& cImage, DXGI_FORMAT format, ScratchImage& image } else { - if ( !IsValid(format) ) + if (!IsValid(format)) return E_INVALIDARG; - if ( IsTypeless(format) || IsPlanar(format) || IsPalettized(format) ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + 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 ); - if ( FAILED(hr) ) + HRESULT hr = image.Initialize2D(format, cImage.width, cImage.height, 1, 1); + if (FAILED(hr)) return hr; - const Image *img = image.GetImage( 0, 0, 0 ); - if ( !img ) + const Image *img = image.GetImage(0, 0, 0); + if (!img) { image.Release(); return E_POINTER; } // Decompress single image - hr = _DecompressBC( cImage, *img ); - if ( FAILED(hr) ) + hr = DecompressBC(cImage, *img); + if (FAILED(hr)) image.Release(); return hr; } _Use_decl_annotations_ -HRESULT Decompress( const Image* cImages, size_t nimages, const TexMetadata& metadata, - DXGI_FORMAT format, ScratchImage& images ) +HRESULT DirectX::Decompress( + const Image* cImages, + size_t nimages, + const TexMetadata& metadata, + DXGI_FORMAT format, + ScratchImage& images) { - if ( !cImages || !nimages ) + if (!cImages || !nimages) return E_INVALIDARG; - if ( !IsCompressed(metadata.format) || IsCompressed(format) ) + if (!IsCompressed(metadata.format) || IsCompressed(format)) return E_INVALIDARG; - if ( format == DXGI_FORMAT_UNKNOWN ) + if (format == DXGI_FORMAT_UNKNOWN) { // Pick a default decompressed format based on BC input format - format = _DefaultDecompress( cImages[0].format ); - if ( format == DXGI_FORMAT_UNKNOWN ) + format = DefaultDecompress(cImages[0].format); + if (format == DXGI_FORMAT_UNKNOWN) { // Input is not a compressed format return E_FAIL; @@ -769,53 +797,53 @@ HRESULT Decompress( const Image* cImages, size_t nimages, const TexMetadata& met } else { - if ( !IsValid(format) ) + if (!IsValid(format)) return E_INVALIDARG; - if ( IsTypeless(format) || IsPlanar(format) || IsPalettized(format) ) - HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if (IsTypeless(format) || IsPlanar(format) || IsPalettized(format)) + HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } images.Release(); TexMetadata mdata2 = metadata; mdata2.format = format; - HRESULT hr = images.Initialize( mdata2 ); - if ( FAILED(hr) ) + HRESULT hr = images.Initialize(mdata2); + if (FAILED(hr)) return hr; - if ( nimages != images.GetImageCount() ) + if (nimages != images.GetImageCount()) { images.Release(); return E_FAIL; } const Image* dest = images.GetImages(); - if ( !dest ) + if (!dest) { images.Release(); return E_POINTER; } - for( size_t index=0; index < nimages; ++index ) + for (size_t index = 0; index < nimages; ++index) { - assert( dest[ index ].format == format ); + assert(dest[index].format == format); - const Image& src = cImages[ index ]; - if ( !IsCompressed( src.format ) ) + const Image& src = cImages[index]; + if (!IsCompressed(src.format)) { images.Release(); return E_FAIL; } - if ( src.width != dest[ index ].width || src.height != dest[ index ].height ) + if (src.width != dest[index].width || src.height != dest[index].height) { images.Release(); return E_FAIL; } - hr = _DecompressBC( src, dest[ index ] ); - if ( FAILED(hr) ) + hr = DecompressBC(src, dest[index]); + if (FAILED(hr)) { images.Release(); return hr; @@ -824,5 +852,3 @@ HRESULT Decompress( const Image* cImages, size_t nimages, const TexMetadata& met return S_OK; } - -}; // namespace diff --git a/DirectXTex/DirectXTexCompressGPU.cpp b/DirectXTex/DirectXTexCompressGPU.cpp index 46b1a86..09f62dd 100644 --- a/DirectXTex/DirectXTexCompressGPU.cpp +++ b/DirectXTex/DirectXTexCompressGPU.cpp @@ -17,178 +17,190 @@ #include "bcdirectcompute.h" -namespace DirectX +using namespace DirectX; + +namespace { - -inline static DWORD _GetSRGBFlags( _In_ DWORD compress ) -{ - static_assert( TEX_COMPRESS_SRGB_IN == TEX_FILTER_SRGB_IN, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*" ); - static_assert( TEX_COMPRESS_SRGB_OUT == TEX_FILTER_SRGB_OUT, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*" ); - static_assert( TEX_COMPRESS_SRGB == TEX_FILTER_SRGB, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*" ); - return ( compress & TEX_COMPRESS_SRGB ); -} - - -//------------------------------------------------------------------------------------- -// Converts to R8G8B8A8_UNORM or R8G8B8A8_UNORM_SRGB doing any conversion logic needed -//------------------------------------------------------------------------------------- -static HRESULT _ConvertToRGBA32( _In_ const Image& srcImage, _In_ ScratchImage& image, bool srgb, _In_ DWORD filter ) -{ - if ( !srcImage.pixels ) - return E_POINTER; - - DXGI_FORMAT format = srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM; - - HRESULT hr = image.Initialize2D( format, srcImage.width, srcImage.height, 1, 1 ); - if ( FAILED(hr) ) - return hr; - - const Image *img = image.GetImage( 0, 0, 0 ); - if ( !img ) + inline DWORD GetSRGBFlags(_In_ DWORD compress) { - image.Release(); - return E_POINTER; + static_assert(TEX_COMPRESS_SRGB_IN == TEX_FILTER_SRGB_IN, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*"); + static_assert(TEX_COMPRESS_SRGB_OUT == TEX_FILTER_SRGB_OUT, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*"); + static_assert(TEX_COMPRESS_SRGB == TEX_FILTER_SRGB, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*"); + return (compress & TEX_COMPRESS_SRGB); } - uint8_t* pDest = img->pixels; - if ( !pDest ) + + //------------------------------------------------------------------------------------- + // Converts to R8G8B8A8_UNORM or R8G8B8A8_UNORM_SRGB doing any conversion logic needed + //------------------------------------------------------------------------------------- + HRESULT ConvertToRGBA32( + const Image& srcImage, + ScratchImage& image, + bool srgb, + DWORD filter) { - image.Release(); - return E_POINTER; - } - - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( ( sizeof(XMVECTOR) * srcImage.width ), 16 ) ) ); - if ( !scanline ) - { - image.Release(); - return E_OUTOFMEMORY; - } - - const uint8_t *pSrc = srcImage.pixels; - for( size_t h = 0; h < srcImage.height; ++h ) - { - if ( !_LoadScanline( scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) ) - { - image.Release(); - return E_FAIL; - } - - _ConvertScanline( scanline.get(), srcImage.width, format, srcImage.format, filter ); - - if ( !_StoreScanline( pDest, img->rowPitch, format, scanline.get(), srcImage.width ) ) - { - image.Release(); - return E_FAIL; - } - - pSrc += srcImage.rowPitch; - pDest += img->rowPitch; - } - - return S_OK; -} - - -//------------------------------------------------------------------------------------- -// Converts to DXGI_FORMAT_R32G32B32A32_FLOAT doing any conversion logic needed -//------------------------------------------------------------------------------------- -static HRESULT _ConvertToRGBAF32( const Image& srcImage, ScratchImage& image, _In_ DWORD filter ) -{ - if ( !srcImage.pixels ) - return E_POINTER; - - HRESULT hr = image.Initialize2D( DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.width, srcImage.height, 1, 1 ); - if ( FAILED(hr) ) - return hr; - - const Image *img = image.GetImage( 0, 0, 0 ); - if ( !img ) - { - image.Release(); - return E_POINTER; - } - - uint8_t* pDest = img->pixels; - if ( !pDest ) - { - image.Release(); - return E_POINTER; - } - - const uint8_t *pSrc = srcImage.pixels; - for( size_t h = 0; h < srcImage.height; ++h ) - { - if ( !_LoadScanline( reinterpret_cast(pDest), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) ) - { - image.Release(); - return E_FAIL; - } - - _ConvertScanline( reinterpret_cast(pDest), srcImage.width, DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.format, filter ); - - pSrc += srcImage.rowPitch; - pDest += img->rowPitch; - } - - return S_OK; -} - - -//------------------------------------------------------------------------------------- -// Compress using GPU, converting to the proper input format for the shader if needed -//------------------------------------------------------------------------------------- -inline static HRESULT _GPUCompress( _In_ GPUCompressBC* gpubc, _In_ const Image& srcImage, _In_ const Image& destImage, _In_ DWORD compress ) -{ - if ( !gpubc ) - return E_POINTER; - - assert( srcImage.pixels && destImage.pixels ); - - DXGI_FORMAT format = gpubc->GetSourceFormat(); - - if ( srcImage.format == format ) - { - // Input is already in our required source format - return gpubc->Compress( srcImage, destImage ); - } - else - { - // Convert format and then use as the source image - ScratchImage image; - HRESULT hr; - - DWORD srgb = _GetSRGBFlags( compress ); - - switch( format ) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: - hr = _ConvertToRGBA32( srcImage, image, false, srgb ); - break; - - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - hr = _ConvertToRGBA32( srcImage, image, true, srgb ); - break; - - case DXGI_FORMAT_R32G32B32A32_FLOAT: - hr = _ConvertToRGBAF32( srcImage, image, srgb ); - break; - - default: - hr = E_UNEXPECTED; - break; - } - - if ( FAILED(hr) ) - return hr; - - const Image *img = image.GetImage( 0, 0, 0 ); - if ( !img ) + if (!srcImage.pixels) return E_POINTER; - return gpubc->Compress( *img, destImage ); - } -} + DXGI_FORMAT format = srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM; + HRESULT hr = image.Initialize2D(format, srcImage.width, srcImage.height, 1, 1); + if (FAILED(hr)) + return hr; + + const Image *img = image.GetImage(0, 0, 0); + if (!img) + { + image.Release(); + return E_POINTER; + } + + uint8_t* pDest = img->pixels; + if (!pDest) + { + image.Release(); + return E_POINTER; + } + + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc((sizeof(XMVECTOR) * srcImage.width), 16))); + if (!scanline) + { + image.Release(); + return E_OUTOFMEMORY; + } + + const uint8_t *pSrc = srcImage.pixels; + for (size_t h = 0; h < srcImage.height; ++h) + { + if (!_LoadScanline(scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format)) + { + image.Release(); + return E_FAIL; + } + + _ConvertScanline(scanline.get(), srcImage.width, format, srcImage.format, filter); + + if (!_StoreScanline(pDest, img->rowPitch, format, scanline.get(), srcImage.width)) + { + image.Release(); + return E_FAIL; + } + + pSrc += srcImage.rowPitch; + pDest += img->rowPitch; + } + + return S_OK; + } + + + //------------------------------------------------------------------------------------- + // Converts to DXGI_FORMAT_R32G32B32A32_FLOAT doing any conversion logic needed + //------------------------------------------------------------------------------------- + HRESULT ConvertToRGBAF32( + const Image& srcImage, + ScratchImage& image, + DWORD filter) + { + if (!srcImage.pixels) + return E_POINTER; + + HRESULT hr = image.Initialize2D(DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.width, srcImage.height, 1, 1); + if (FAILED(hr)) + return hr; + + const Image *img = image.GetImage(0, 0, 0); + if (!img) + { + image.Release(); + return E_POINTER; + } + + uint8_t* pDest = img->pixels; + if (!pDest) + { + image.Release(); + return E_POINTER; + } + + const uint8_t *pSrc = srcImage.pixels; + for (size_t h = 0; h < srcImage.height; ++h) + { + if (!_LoadScanline(reinterpret_cast(pDest), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format)) + { + image.Release(); + return E_FAIL; + } + + _ConvertScanline(reinterpret_cast(pDest), srcImage.width, DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.format, filter); + + pSrc += srcImage.rowPitch; + pDest += img->rowPitch; + } + + return S_OK; + } + + + //------------------------------------------------------------------------------------- + // Compress using GPU, converting to the proper input format for the shader if needed + //------------------------------------------------------------------------------------- + inline HRESULT GPUCompress( + _In_ GPUCompressBC* gpubc, + const Image& srcImage, + const Image& destImage, + DWORD compress) + { + if (!gpubc) + return E_POINTER; + + assert(srcImage.pixels && destImage.pixels); + + DXGI_FORMAT format = gpubc->GetSourceFormat(); + + if (srcImage.format == format) + { + // Input is already in our required source format + return gpubc->Compress(srcImage, destImage); + } + else + { + // Convert format and then use as the source image + ScratchImage image; + HRESULT hr; + + DWORD srgb = GetSRGBFlags(compress); + + switch (format) + { + case DXGI_FORMAT_R8G8B8A8_UNORM: + hr = ConvertToRGBA32(srcImage, image, false, srgb); + break; + + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + hr = ConvertToRGBA32(srcImage, image, true, srgb); + break; + + case DXGI_FORMAT_R32G32B32A32_FLOAT: + hr = ConvertToRGBAF32(srcImage, image, srgb); + break; + + default: + hr = E_UNEXPECTED; + break; + } + + if (FAILED(hr)) + return hr; + + const Image *img = image.GetImage(0, 0, 0); + if (!img) + return E_POINTER; + + return gpubc->Compress(*img, destImage); + } + } +}; //===================================================================================== // Entry-points @@ -198,205 +210,216 @@ inline static HRESULT _GPUCompress( _In_ GPUCompressBC* gpubc, _In_ const Image& // Compression //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT Compress( ID3D11Device* pDevice, const Image& srcImage, DXGI_FORMAT format, DWORD compress, float alphaWeight, ScratchImage& image ) +HRESULT DirectX::Compress( + ID3D11Device* pDevice, + const Image& srcImage, + DXGI_FORMAT format, + DWORD compress, + float alphaWeight, + ScratchImage& image) { - if ( !pDevice || IsCompressed(srcImage.format) || !IsCompressed(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 ); + 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 ) + std::unique_ptr gpubc(new (std::nothrow) GPUCompressBC); + if (!gpubc) return E_OUTOFMEMORY; - HRESULT hr = gpubc->Initialize( pDevice ); - if ( FAILED(hr) ) + HRESULT hr = gpubc->Initialize(pDevice); + if (FAILED(hr)) return hr; - hr = gpubc->Prepare( srcImage.width, srcImage.height, format, alphaWeight, !(compress & TEX_COMPRESS_BC7_USE_3SUBSETS) ); - if ( FAILED(hr) ) + hr = gpubc->Prepare(srcImage.width, srcImage.height, format, alphaWeight, !(compress & TEX_COMPRESS_BC7_USE_3SUBSETS)); + if (FAILED(hr)) return hr; // Create workspace for result - hr = image.Initialize2D( format, srcImage.width, srcImage.height, 1, 1 ); - if ( FAILED(hr) ) + hr = image.Initialize2D(format, srcImage.width, srcImage.height, 1, 1); + if (FAILED(hr)) return hr; - const Image *img = image.GetImage( 0, 0, 0 ); - if ( !img ) + const Image *img = image.GetImage(0, 0, 0); + if (!img) { image.Release(); return E_POINTER; } - hr = _GPUCompress( gpubc.get(), srcImage, *img, compress ); - if ( FAILED(hr) ) + hr = GPUCompress(gpubc.get(), srcImage, *img, compress); + if (FAILED(hr)) image.Release(); return hr; } _Use_decl_annotations_ -HRESULT Compress( ID3D11Device* pDevice, const Image* srcImages, size_t nimages, const TexMetadata& metadata, - DXGI_FORMAT format, DWORD compress, float alphaWeight, ScratchImage& cImages ) +HRESULT DirectX::Compress( + ID3D11Device* pDevice, + const Image* srcImages, + size_t nimages, + const TexMetadata& metadata, + DXGI_FORMAT format, + DWORD compress, + float alphaWeight, + ScratchImage& cImages) { - if ( !pDevice || !srcImages || !nimages ) + if (!pDevice || !srcImages || !nimages) return E_INVALIDARG; - if ( IsCompressed(metadata.format) || !IsCompressed(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 ); + if (IsTypeless(format) + || IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format)) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); cImages.Release(); // Setup GPU compressor - std::unique_ptr gpubc( new (std::nothrow) GPUCompressBC ); - if ( !gpubc ) + std::unique_ptr gpubc(new (std::nothrow) GPUCompressBC); + if (!gpubc) return E_OUTOFMEMORY; - HRESULT hr = gpubc->Initialize( pDevice ); - if ( FAILED(hr) ) + HRESULT hr = gpubc->Initialize(pDevice); + if (FAILED(hr)) return hr; // Create workspace for result TexMetadata mdata2 = metadata; mdata2.format = format; - hr = cImages.Initialize( mdata2 ); - if ( FAILED(hr) ) + hr = cImages.Initialize(mdata2); + if (FAILED(hr)) return hr; - if ( nimages != cImages.GetImageCount() ) + if (nimages != cImages.GetImageCount()) { cImages.Release(); return E_FAIL; } const Image* dest = cImages.GetImages(); - if ( !dest ) + if (!dest) { cImages.Release(); return E_POINTER; } // Process images (ordered by size) - switch( metadata.dimension ) + switch (metadata.dimension) { case TEX_DIMENSION_TEXTURE1D: case TEX_DIMENSION_TEXTURE2D: - { - size_t w = metadata.width; - size_t h = metadata.height; + { + size_t w = metadata.width; + size_t h = metadata.height; - for( size_t level=0; level < metadata.mipLevels; ++level ) + for (size_t level = 0; level < metadata.mipLevels; ++level) + { + hr = gpubc->Prepare(w, h, format, alphaWeight, !(compress & TEX_COMPRESS_BC7_USE_3SUBSETS)); + if (FAILED(hr)) { - hr = gpubc->Prepare( w, h, format, alphaWeight, !(compress & TEX_COMPRESS_BC7_USE_3SUBSETS) ); - if ( FAILED(hr) ) + cImages.Release(); + return hr; + } + + for (size_t item = 0; item < metadata.arraySize; ++item) + { + size_t index = metadata.ComputeIndex(level, item, 0); + if (index >= nimages) + { + cImages.Release(); + return E_FAIL; + } + + assert(dest[index].format == format); + + const Image& src = srcImages[index]; + + if (src.width != dest[index].width || src.height != dest[index].height) + { + cImages.Release(); + return E_FAIL; + } + + hr = GPUCompress(gpubc.get(), src, dest[index], compress); + if (FAILED(hr)) { cImages.Release(); return hr; } - - for( size_t item = 0; item < metadata.arraySize; ++item ) - { - size_t index = metadata.ComputeIndex( level, item, 0 ); - if ( index >= nimages ) - { - cImages.Release(); - return E_FAIL; - } - - assert( dest[ index ].format == format ); - - const Image& src = srcImages[ index ]; - - if ( src.width != dest[ index ].width || src.height != dest[ index ].height ) - { - cImages.Release(); - return E_FAIL; - } - - hr = _GPUCompress( gpubc.get(), src, dest[ index ], compress ); - if ( FAILED(hr) ) - { - cImages.Release(); - return hr; - } - } - - if ( h > 1 ) - h >>= 1; - - if ( w > 1 ) - w >>= 1; } + + if (h > 1) + h >>= 1; + + if (w > 1) + w >>= 1; } - break; + } + break; case TEX_DIMENSION_TEXTURE3D: - { - size_t w = metadata.width; - size_t h = metadata.height; - size_t d = metadata.depth; + { + size_t w = metadata.width; + size_t h = metadata.height; + size_t d = metadata.depth; - for( size_t level=0; level < metadata.mipLevels; ++level ) + for (size_t level = 0; level < metadata.mipLevels; ++level) + { + hr = gpubc->Prepare(w, h, format, alphaWeight, !(compress & TEX_COMPRESS_BC7_USE_3SUBSETS)); + if (FAILED(hr)) { - hr = gpubc->Prepare( w, h, format, alphaWeight, !(compress & TEX_COMPRESS_BC7_USE_3SUBSETS) ); - if ( FAILED(hr) ) + cImages.Release(); + return hr; + } + + for (size_t slice = 0; slice < d; ++slice) + { + size_t index = metadata.ComputeIndex(level, 0, slice); + if (index >= nimages) + { + cImages.Release(); + return E_FAIL; + } + + assert(dest[index].format == format); + + const Image& src = srcImages[index]; + + if (src.width != dest[index].width || src.height != dest[index].height) + { + cImages.Release(); + return E_FAIL; + } + + hr = GPUCompress(gpubc.get(), src, dest[index], compress); + if (FAILED(hr)) { cImages.Release(); return hr; } - - for( size_t slice=0; slice < d; ++slice ) - { - size_t index = metadata.ComputeIndex( level, 0, slice ); - if ( index >= nimages ) - { - cImages.Release(); - return E_FAIL; - } - - assert( dest[ index ].format == format ); - - const Image& src = srcImages[ index ]; - - if ( src.width != dest[ index ].width || src.height != dest[ index ].height ) - { - cImages.Release(); - return E_FAIL; - } - - hr = _GPUCompress( gpubc.get(), src, dest[ index ], compress ); - if ( FAILED(hr) ) - { - cImages.Release(); - return hr; - } - } - - if ( h > 1 ) - h >>= 1; - - if ( w > 1 ) - w >>= 1; - - if ( d > 1 ) - d >>= 1; } + + if (h > 1) + h >>= 1; + + if (w > 1) + w >>= 1; + + if (d > 1) + d >>= 1; } - break; + } + break; default: - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } return S_OK; } - -}; // namespace diff --git a/DirectXTex/DirectXTexConvert.cpp b/DirectXTex/DirectXTexConvert.cpp index f6999d9..7af37f4 100644 --- a/DirectXTex/DirectXTexConvert.cpp +++ b/DirectXTex/DirectXTexConvert.cpp @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------------- // DirectXTexConvert.cpp // -// DirectX Texture Library - Image conversion +// DirectX Texture Library - Image pixel format conversion // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO @@ -15,6 +15,7 @@ #include "directxtexp.h" +using namespace DirectX; using namespace DirectX::PackedVector; using Microsoft::WRL::ComPtr; @@ -24,7 +25,7 @@ namespace { uint32_t IValue = reinterpret_cast(&Value)[0]; - if ( IValue & 0x80000000U ) + if (IValue & 0x80000000U) { // Positive only return 0; @@ -49,11 +50,11 @@ namespace IValue += 0xC2000000U; } - return ((IValue + 0x7FFFU + ((IValue >> 16U) & 1U)) >> 16U)&0x3FFU; + return ((IValue + 0x7FFFU + ((IValue >> 16U) & 1U)) >> 16U) & 0x3FFU; } } - inline float FloatFrom7e3( uint32_t Value ) + inline float FloatFrom7e3(uint32_t Value) { uint32_t Mantissa = (uint32_t)(Value & 0x7F); @@ -81,7 +82,7 @@ namespace } uint32_t Result = ((Exponent + 124) << 23) | // Exponent - (Mantissa << 16); // Mantissa + (Mantissa << 16); // Mantissa return reinterpret_cast(&Result)[0]; } @@ -90,7 +91,7 @@ namespace { uint32_t IValue = reinterpret_cast(&Value)[0]; - if ( IValue & 0x80000000U ) + if (IValue & 0x80000000U) { // Positive only return 0; @@ -115,11 +116,11 @@ namespace IValue += 0xC4000000U; } - return ((IValue + 0xFFFFU + ((IValue >> 17U) & 1U)) >> 17U)&0x3FFU; + return ((IValue + 0xFFFFU + ((IValue >> 17U) & 1U)) >> 17U) & 0x3FFU; } } - inline float FloatFrom6e4( uint32_t Value ) + inline float FloatFrom6e4(uint32_t Value) { uint32_t Mantissa = (uint32_t)(Value & 0x3F); @@ -147,13 +148,13 @@ namespace } uint32_t Result = ((Exponent + 120) << 23) | // Exponent - (Mantissa << 17); // Mantissa + (Mantissa << 17); // Mantissa return reinterpret_cast(&Result)[0]; } #if DIRECTX_MATH_VERSION >= 310 - #define StoreFloat3SE XMStoreFloat3SE +#define StoreFloat3SE XMStoreFloat3SE #else inline void XM_CALLCONV StoreFloat3SE(_Out_ XMFLOAT3SE* pDestination, DirectX::FXMVECTOR V) { @@ -185,57 +186,58 @@ namespace fi.i = 0x83000000 - (exp << 23); float ScaleR = fi.f; - pDestination->xm = static_cast( lroundf(x * ScaleR) ); - pDestination->ym = static_cast( lroundf(y * ScaleR) ); - pDestination->zm = static_cast( lroundf(z * ScaleR) ); + pDestination->xm = static_cast(lroundf(x * ScaleR)); + pDestination->ym = static_cast(lroundf(y * ScaleR)); + pDestination->zm = static_cast(lroundf(z * ScaleR)); } #endif -}; -namespace DirectX -{ -static const XMVECTORF32 g_Grayscale = { 0.2125f, 0.7154f, 0.0721f, 0.0f }; -static const XMVECTORF32 g_HalfMin = { -65504.f, -65504.f, -65504.f, -65504.f }; -static const XMVECTORF32 g_HalfMax = { 65504.f, 65504.f, 65504.f, 65504.f }; -static const XMVECTORF32 g_8BitBias = { 0.5f/255.f, 0.5f/255.f, 0.5f/255.f, 0.5f/255.f }; + const XMVECTORF32 g_Grayscale = { 0.2125f, 0.7154f, 0.0721f, 0.0f }; + const XMVECTORF32 g_HalfMin = { -65504.f, -65504.f, -65504.f, -65504.f }; + const XMVECTORF32 g_HalfMax = { 65504.f, 65504.f, 65504.f, 65504.f }; + const XMVECTORF32 g_8BitBias = { 0.5f / 255.f, 0.5f / 255.f, 0.5f / 255.f, 0.5f / 255.f }; +} //------------------------------------------------------------------------------------- // Copies an image row with optional clearing of alpha value to 1.0 // (can be used in place as well) otherwise copies the image row unmodified. //------------------------------------------------------------------------------------- -void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize)) - _When_(pDestination != pSource, _Out_writes_bytes_(outSize)) - LPVOID pDestination, _In_ size_t outSize, - _In_reads_bytes_(inSize) LPCVOID pSource, _In_ size_t inSize, - _In_ DXGI_FORMAT format, _In_ DWORD flags) +_Use_decl_annotations_ +void DirectX::_CopyScanline( + void* pDestination, + size_t outSize, + const void* pSource, + size_t inSize, + DXGI_FORMAT format, + DWORD flags) { - assert( pDestination && outSize > 0 ); - assert( pSource && inSize > 0 ); - assert( IsValid(format) && !IsPalettized(format) ); + assert(pDestination && outSize > 0); + assert(pSource && inSize > 0); + assert(IsValid(format) && !IsPalettized(format)); - if ( flags & TEXP_SCANLINE_SETALPHA ) + if (flags & TEXP_SCANLINE_SETALPHA) { - switch( static_cast(format) ) + switch (static_cast(format)) { - //----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- case DXGI_FORMAT_R32G32B32A32_TYPELESS: case DXGI_FORMAT_R32G32B32A32_FLOAT: case DXGI_FORMAT_R32G32B32A32_UINT: case DXGI_FORMAT_R32G32B32A32_SINT: - if ( inSize >= 16 && outSize >= 16 ) + if (inSize >= 16 && outSize >= 16) { uint32_t alpha; - if ( format == DXGI_FORMAT_R32G32B32A32_FLOAT ) + if (format == DXGI_FORMAT_R32G32B32A32_FLOAT) alpha = 0x3f800000; - else if ( format == DXGI_FORMAT_R32G32B32A32_SINT ) + else if (format == DXGI_FORMAT_R32G32B32A32_SINT) alpha = 0x7fffffff; else alpha = 0xffffffff; - if ( pDestination == pSource ) + if (pDestination == pSource) { uint32_t *dPtr = reinterpret_cast (pDestination); - for( size_t count = 0; count < ( outSize - 15 ); count += 16 ) + for (size_t count = 0; count < (outSize - 15); count += 16) { dPtr += 3; *(dPtr++) = alpha; @@ -245,8 +247,8 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize { 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 - 15 ); count += 16 ) + size_t size = std::min(outSize, inSize); + for (size_t count = 0; count < (size - 15); count += 16) { *(dPtr++) = *(sPtr++); *(dPtr++) = *(sPtr++); @@ -258,7 +260,7 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize } return; - //----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- case DXGI_FORMAT_R16G16B16A16_TYPELESS: case DXGI_FORMAT_R16G16B16A16_FLOAT: case DXGI_FORMAT_R16G16B16A16_UNORM: @@ -266,20 +268,20 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize case DXGI_FORMAT_R16G16B16A16_SNORM: case DXGI_FORMAT_R16G16B16A16_SINT: case DXGI_FORMAT_Y416: - if ( inSize >= 8 && outSize >= 8 ) + if (inSize >= 8 && outSize >= 8) { uint16_t alpha; - if ( format == DXGI_FORMAT_R16G16B16A16_FLOAT ) + if (format == DXGI_FORMAT_R16G16B16A16_FLOAT) alpha = 0x3c00; - else if ( format == DXGI_FORMAT_R16G16B16A16_SNORM || format == DXGI_FORMAT_R16G16B16A16_SINT ) + else if (format == DXGI_FORMAT_R16G16B16A16_SNORM || format == DXGI_FORMAT_R16G16B16A16_SINT) alpha = 0x7fff; else alpha = 0xffff; - if ( pDestination == pSource ) + if (pDestination == pSource) { uint16_t *dPtr = reinterpret_cast(pDestination); - for( size_t count = 0; count < ( outSize - 7 ); count += 8 ) + for (size_t count = 0; count < (outSize - 7); count += 8) { dPtr += 3; *(dPtr++) = alpha; @@ -289,8 +291,8 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize { const uint16_t * __restrict sPtr = reinterpret_cast(pSource); uint16_t * __restrict dPtr = reinterpret_cast(pDestination); - size_t size = std::min( outSize, inSize ); - for( size_t count = 0; count < ( size - 7 ); count += 8 ) + size_t size = std::min(outSize, inSize); + for (size_t count = 0; count < (size - 7); count += 8) { *(dPtr++) = *(sPtr++); *(dPtr++) = *(sPtr++); @@ -302,7 +304,7 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize } return; - //----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- case DXGI_FORMAT_R10G10B10A2_TYPELESS: case DXGI_FORMAT_R10G10B10A2_UNORM: case DXGI_FORMAT_R10G10B10A2_UINT: @@ -311,12 +313,12 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize case XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT: case XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT: case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM: - if ( inSize >= 4 && outSize >= 4 ) + if (inSize >= 4 && outSize >= 4) { - if ( pDestination == pSource ) + if (pDestination == pSource) { uint32_t *dPtr = reinterpret_cast(pDestination); - for( size_t count = 0; count < ( outSize - 3 ); count += 4 ) + for (size_t count = 0; count < (outSize - 3); count += 4) { *dPtr |= 0xC0000000; ++dPtr; @@ -326,8 +328,8 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize { 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 ) + size_t size = std::min(outSize, inSize); + for (size_t count = 0; count < (size - 3); count += 4) { *(dPtr++) = *(sPtr++) | 0xC0000000; } @@ -335,7 +337,7 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize } return; - //----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- case DXGI_FORMAT_R8G8B8A8_TYPELESS: case DXGI_FORMAT_R8G8B8A8_UNORM: case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: @@ -346,14 +348,14 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize case DXGI_FORMAT_B8G8R8A8_TYPELESS: case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: case DXGI_FORMAT_AYUV: - if ( inSize >= 4 && outSize >= 4 ) + if (inSize >= 4 && outSize >= 4) { - const uint32_t alpha = ( format == DXGI_FORMAT_R8G8B8A8_SNORM || format == DXGI_FORMAT_R8G8B8A8_SINT ) ? 0x7f000000 : 0xff000000; + const uint32_t alpha = (format == DXGI_FORMAT_R8G8B8A8_SNORM || format == DXGI_FORMAT_R8G8B8A8_SINT) ? 0x7f000000 : 0xff000000; - if ( pDestination == pSource ) + if (pDestination == pSource) { uint32_t *dPtr = reinterpret_cast(pDestination); - for( size_t count = 0; count < ( outSize - 3 ); count += 4 ) + for (size_t count = 0; count < (outSize - 3); count += 4) { uint32_t t = *dPtr & 0xFFFFFF; t |= alpha; @@ -364,8 +366,8 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize { 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 ) + size_t size = std::min(outSize, inSize); + for (size_t count = 0; count < (size - 3); count += 4) { uint32_t t = *(sPtr++) & 0xFFFFFF; t |= alpha; @@ -375,14 +377,14 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize } return; - //----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- case DXGI_FORMAT_B5G5R5A1_UNORM: - if ( inSize >= 2 && outSize >= 2 ) + if (inSize >= 2 && outSize >= 2) { - if ( pDestination == pSource ) + if (pDestination == pSource) { uint16_t *dPtr = reinterpret_cast(pDestination); - for( size_t count = 0; count < ( outSize - 1 ); count += 2 ) + for (size_t count = 0; count < (outSize - 1); count += 2) { *(dPtr++) |= 0x8000; } @@ -391,8 +393,8 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize { const uint16_t * __restrict sPtr = reinterpret_cast(pSource); uint16_t * __restrict dPtr = reinterpret_cast(pDestination); - size_t size = std::min( outSize, inSize ); - for( size_t count = 0; count < ( size - 1 ); count += 2 ) + size_t size = std::min(outSize, inSize); + for (size_t count = 0; count < (size - 1); count += 2) { *(dPtr++) = *(sPtr++) | 0x8000; } @@ -400,19 +402,19 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize } return; - //----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- case DXGI_FORMAT_A8_UNORM: - memset( pDestination, 0xff, outSize ); + memset(pDestination, 0xff, outSize); return; - //----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- case DXGI_FORMAT_B4G4R4A4_UNORM: - if ( inSize >= 2 && outSize >= 2 ) + if (inSize >= 2 && outSize >= 2) { - if ( pDestination == pSource ) + if (pDestination == pSource) { uint16_t *dPtr = reinterpret_cast(pDestination); - for( size_t count = 0; count < ( outSize - 1 ); count += 2 ) + for (size_t count = 0; count < (outSize - 1); count += 2) { *(dPtr++) |= 0xF000; } @@ -421,8 +423,8 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize { const uint16_t * __restrict sPtr = reinterpret_cast(pSource); uint16_t * __restrict dPtr = reinterpret_cast(pDestination); - size_t size = std::min( outSize, inSize ); - for( size_t count = 0; count < ( size - 1 ); count += 2 ) + size_t size = std::min(outSize, inSize); + for (size_t count = 0; count < (size - 1); count += 2) { *(dPtr++) = *(sPtr++) | 0xF000; } @@ -433,11 +435,11 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize } // Fall-through case is to just use memcpy (assuming this is not an in-place operation) - if ( pDestination == pSource ) + if (pDestination == pSource) return; - size_t size = std::min( outSize, inSize ); - memcpy_s( pDestination, outSize, pSource, size ); + size_t size = std::min(outSize, inSize); + memcpy_s(pDestination, outSize, pSource, size); } @@ -446,36 +448,42 @@ void _CopyScanline(_When_(pDestination == pSource, _Inout_updates_bytes_(outSize // (can be used in place as well) otherwise copies the image row unmodified. //------------------------------------------------------------------------------------- _Use_decl_annotations_ -void _SwizzleScanline( LPVOID pDestination, size_t outSize, LPCVOID pSource, size_t inSize, DXGI_FORMAT format, DWORD flags ) +void DirectX::_SwizzleScanline( + void* pDestination, + size_t outSize, + const void* pSource, + size_t inSize, + DXGI_FORMAT format, + DWORD flags) { - assert( pDestination && outSize > 0 ); - assert( pSource && inSize > 0 ); - assert( IsValid(format) && !IsPlanar(format) && !IsPalettized(format) ); + assert(pDestination && outSize > 0); + assert(pSource && inSize > 0); + assert(IsValid(format) && !IsPlanar(format) && !IsPalettized(format)); - switch( static_cast(format) ) + switch (static_cast(format)) { - //--------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------- case DXGI_FORMAT_R10G10B10A2_TYPELESS: case DXGI_FORMAT_R10G10B10A2_UNORM: case DXGI_FORMAT_R10G10B10A2_UINT: case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM: - if ( inSize >= 4 && outSize >= 4 ) + if (inSize >= 4 && outSize >= 4) { - if ( flags & TEXP_SCANLINE_LEGACY ) + if (flags & TEXP_SCANLINE_LEGACY) { // Swap Red (R) and Blue (B) channel (used for D3DFMT_A2R10G10B10 legacy sources) - if ( pDestination == pSource ) + if (pDestination == pSource) { uint32_t *dPtr = reinterpret_cast(pDestination); - for( size_t count = 0; count < ( outSize - 3 ); count += 4 ) + for (size_t count = 0; count < (outSize - 3); count += 4) { uint32_t t = *dPtr; uint32_t t1 = (t & 0x3ff00000) >> 20; uint32_t t2 = (t & 0x000003ff) << 20; uint32_t t3 = (t & 0x000ffc00); - uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xC0000000 : (t & 0xC0000000); + uint32_t ta = (flags & TEXP_SCANLINE_SETALPHA) ? 0xC0000000 : (t & 0xC0000000); *(dPtr++) = t1 | t2 | t3 | ta; } @@ -484,15 +492,15 @@ void _SwizzleScanline( LPVOID pDestination, size_t outSize, LPCVOID pSource, siz { 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 ) + 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 & 0x3ff00000) >> 20; uint32_t t2 = (t & 0x000003ff) << 20; uint32_t t3 = (t & 0x000ffc00); - uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xC0000000 : (t & 0xC0000000); + uint32_t ta = (flags & TEXP_SCANLINE_SETALPHA) ? 0xC0000000 : (t & 0xC0000000); *(dPtr++) = t1 | t2 | t3 | ta; } @@ -502,7 +510,7 @@ void _SwizzleScanline( LPVOID pDestination, size_t outSize, LPCVOID pSource, siz } break; - //--------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------- case DXGI_FORMAT_R8G8B8A8_TYPELESS: case DXGI_FORMAT_R8G8B8A8_UNORM: case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: @@ -512,20 +520,20 @@ void _SwizzleScanline( LPVOID pDestination, size_t outSize, LPCVOID pSource, siz case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: case DXGI_FORMAT_B8G8R8X8_TYPELESS: case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: - if ( inSize >= 4 && outSize >= 4 ) + if (inSize >= 4 && outSize >= 4) { // Swap Red (R) and Blue (B) channels (used to convert from DXGI 1.1 BGR formats to DXGI 1.0 RGB) - if ( pDestination == pSource ) + if (pDestination == pSource) { uint32_t *dPtr = reinterpret_cast(pDestination); - for( size_t count = 0; count < ( outSize - 3 ); count += 4 ) + for (size_t count = 0; count < (outSize - 3); count += 4) { uint32_t t = *dPtr; uint32_t t1 = (t & 0x00ff0000) >> 16; uint32_t t2 = (t & 0x000000ff) << 16; uint32_t t3 = (t & 0x0000ff00); - uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : (t & 0xFF000000); + uint32_t ta = (flags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : (t & 0xFF000000); *(dPtr++) = t1 | t2 | t3 | ta; } @@ -534,15 +542,15 @@ void _SwizzleScanline( LPVOID pDestination, size_t outSize, LPCVOID pSource, siz { 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 ) + 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 & 0x00ff0000) >> 16; uint32_t t2 = (t & 0x000000ff) << 16; uint32_t t3 = (t & 0x0000ff00); - uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : (t & 0xFF000000); + uint32_t ta = (flags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : (t & 0xFF000000); *(dPtr++) = t1 | t2 | t3 | ta; } @@ -551,17 +559,17 @@ void _SwizzleScanline( LPVOID pDestination, size_t outSize, LPCVOID pSource, siz } break; - //--------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------- case DXGI_FORMAT_YUY2: - if ( inSize >= 4 && outSize >= 4 ) + if (inSize >= 4 && outSize >= 4) { - if ( flags & TEXP_SCANLINE_LEGACY ) + if (flags & TEXP_SCANLINE_LEGACY) { // Reorder YUV components (used to convert legacy UYVY -> YUY2) - if ( pDestination == pSource ) + if (pDestination == pSource) { uint32_t *dPtr = reinterpret_cast(pDestination); - for( size_t count = 0; count < ( outSize - 3 ); count += 4 ) + for (size_t count = 0; count < (outSize - 3); count += 4) { uint32_t t = *dPtr; @@ -577,8 +585,8 @@ void _SwizzleScanline( LPVOID pDestination, size_t outSize, LPCVOID pSource, siz { 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 ) + size_t size = std::min(outSize, inSize); + for (size_t count = 0; count < (size - 3); count += 4) { uint32_t t = *(sPtr++); @@ -597,11 +605,11 @@ void _SwizzleScanline( LPVOID pDestination, size_t outSize, LPCVOID pSource, siz } // Fall-through case is to just use memcpy (assuming this is not an in-place operation) - if ( pDestination == pSource ) + if (pDestination == pSource) return; - size_t size = std::min( outSize, inSize ); - memcpy_s( pDestination, outSize, pSource, size ); + size_t size = std::min(outSize, inSize); + memcpy_s(pDestination, outSize, pSource, size); } @@ -610,27 +618,33 @@ void _SwizzleScanline( LPVOID pDestination, size_t outSize, LPCVOID pSource, siz // Returns true if supported, false if expansion case not supported //------------------------------------------------------------------------------------- _Use_decl_annotations_ -bool _ExpandScanline( LPVOID pDestination, size_t outSize, DXGI_FORMAT outFormat, - LPCVOID pSource, size_t inSize, DXGI_FORMAT inFormat, DWORD flags ) +bool DirectX::_ExpandScanline( + void* pDestination, + size_t outSize, + DXGI_FORMAT outFormat, + const void* pSource, + size_t inSize, + DXGI_FORMAT inFormat, + DWORD flags) { - assert( pDestination && outSize > 0 ); - assert( pSource && inSize > 0 ); - assert( IsValid(outFormat) && !IsPlanar(outFormat) && !IsPalettized(outFormat) ); - assert( IsValid(inFormat) && !IsPlanar(inFormat) && !IsPalettized(inFormat) ); + assert(pDestination && outSize > 0); + assert(pSource && inSize > 0); + assert(IsValid(outFormat) && !IsPlanar(outFormat) && !IsPalettized(outFormat)); + assert(IsValid(inFormat) && !IsPlanar(inFormat) && !IsPalettized(inFormat)); - switch( inFormat ) + switch (inFormat) { case DXGI_FORMAT_B5G6R5_UNORM: - if ( outFormat != DXGI_FORMAT_R8G8B8A8_UNORM ) + if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) return false; // DXGI_FORMAT_B5G6R5_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM - if ( inSize >= 2 && outSize >= 4 ) + if (inSize >= 2 && outSize >= 4) { const uint16_t * __restrict sPtr = reinterpret_cast(pSource); uint32_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t ocount = 0, icount = 0; ( ( icount < ( inSize - 1 ) ) && ( ocount < ( outSize - 3 ) ) ); icount += 2, ocount += 4 ) + for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4) { uint16_t t = *(sPtr++); @@ -643,25 +657,25 @@ bool _ExpandScanline( LPVOID pDestination, size_t outSize, DXGI_FORMAT outFormat return true; } return false; - + case DXGI_FORMAT_B5G5R5A1_UNORM: - if ( outFormat != DXGI_FORMAT_R8G8B8A8_UNORM ) + if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) return false; // DXGI_FORMAT_B5G5R5A1_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM - if ( inSize >= 2 && outSize >= 4 ) + if (inSize >= 2 && outSize >= 4) { const uint16_t * __restrict sPtr = reinterpret_cast(pSource); uint32_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t ocount = 0, icount = 0; ( ( icount < ( inSize - 1 ) ) && ( ocount < ( outSize - 3 ) ) ); icount += 2, ocount += 4 ) + for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4) { uint16_t t = *(sPtr++); uint32_t t1 = ((t & 0x7c00) >> 7) | ((t & 0x7000) >> 12); uint32_t t2 = ((t & 0x03e0) << 6) | ((t & 0x0380) << 1); uint32_t t3 = ((t & 0x001f) << 19) | ((t & 0x001c) << 14); - uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : ((t & 0x8000) ? 0xff000000 : 0); + uint32_t ta = (flags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : ((t & 0x8000) ? 0xff000000 : 0); *(dPtr++) = t1 | t2 | t3 | ta; } @@ -670,23 +684,23 @@ bool _ExpandScanline( LPVOID pDestination, size_t outSize, DXGI_FORMAT outFormat return false; case DXGI_FORMAT_B4G4R4A4_UNORM: - if ( outFormat != DXGI_FORMAT_R8G8B8A8_UNORM ) + if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) return false; // DXGI_FORMAT_B4G4R4A4_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM - if ( inSize >= 2 && outSize >= 4 ) + if (inSize >= 2 && outSize >= 4) { const uint16_t * __restrict sPtr = reinterpret_cast(pSource); uint32_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t ocount = 0, icount = 0; ( ( icount < ( inSize - 1 ) ) && ( ocount < ( outSize - 3 ) ) ); icount += 2, ocount += 4 ) + for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4) { uint16_t t = *(sPtr++); uint32_t t1 = ((t & 0x0f00) >> 4) | ((t & 0x0f00) >> 8); uint32_t t2 = ((t & 0x00f0) << 8) | ((t & 0x00f0) << 4); uint32_t t3 = ((t & 0x000f) << 20) | ((t & 0x000f) << 16); - uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : (((t & 0xf000) << 16) | ((t & 0xf000) << 12)); + uint32_t ta = (flags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : (((t & 0xf000) << 16) | ((t & 0xf000) << 12)); *(dPtr++) = t1 | t2 | t3 | ta; } @@ -744,78 +758,82 @@ bool _ExpandScanline( LPVOID pDestination, size_t outSize, DXGI_FORMAT outFormat return false; #pragma warning(suppress: 6101) -_Use_decl_annotations_ bool _LoadScanline( XMVECTOR* pDestination, size_t count, - LPCVOID pSource, size_t size, DXGI_FORMAT format ) +_Use_decl_annotations_ bool DirectX::_LoadScanline( + XMVECTOR* pDestination, + size_t count, + const void* pSource, + size_t size, + DXGI_FORMAT format) { - assert( pDestination && count > 0 && (((uintptr_t)pDestination & 0xF) == 0) ); - assert( pSource && size > 0 ); - assert( IsValid(format) && !IsTypeless(format, false) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format) ); + assert(pDestination && count > 0 && (((uintptr_t)pDestination & 0xF) == 0)); + assert(pSource && size > 0); + assert(IsValid(format) && !IsTypeless(format, false) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format)); XMVECTOR* __restrict dPtr = pDestination; - if ( !dPtr ) + if (!dPtr) return false; const XMVECTOR* ePtr = pDestination + count; - switch( static_cast(format) ) + switch (static_cast(format)) { case DXGI_FORMAT_R32G32B32A32_FLOAT: - { - size_t msize = (size > (sizeof(XMVECTOR)*count)) ? (sizeof(XMVECTOR)*count) : size; - memcpy_s( dPtr, sizeof(XMVECTOR)*count, pSource, msize ); - } - return true; + { + size_t msize = (size > (sizeof(XMVECTOR)*count)) ? (sizeof(XMVECTOR)*count) : size; + memcpy_s(dPtr, sizeof(XMVECTOR)*count, pSource, msize); + } + return true; case DXGI_FORMAT_R32G32B32A32_UINT: - LOAD_SCANLINE( XMUINT4, XMLoadUInt4 ) + LOAD_SCANLINE(XMUINT4, XMLoadUInt4) case DXGI_FORMAT_R32G32B32A32_SINT: - LOAD_SCANLINE( XMINT4, XMLoadSInt4 ) + LOAD_SCANLINE(XMINT4, XMLoadSInt4) case DXGI_FORMAT_R32G32B32_FLOAT: - LOAD_SCANLINE3( XMFLOAT3, XMLoadFloat3, g_XMIdentityR3 ) + LOAD_SCANLINE3(XMFLOAT3, XMLoadFloat3, g_XMIdentityR3) case DXGI_FORMAT_R32G32B32_UINT: - LOAD_SCANLINE3( XMUINT3, XMLoadUInt3, g_XMIdentityR3 ) + LOAD_SCANLINE3(XMUINT3, XMLoadUInt3, g_XMIdentityR3) case DXGI_FORMAT_R32G32B32_SINT: - LOAD_SCANLINE3( XMINT3, XMLoadSInt3, g_XMIdentityR3 ) + LOAD_SCANLINE3(XMINT3, XMLoadSInt3, g_XMIdentityR3) case DXGI_FORMAT_R16G16B16A16_FLOAT: - LOAD_SCANLINE( XMHALF4, XMLoadHalf4 ) + LOAD_SCANLINE(XMHALF4, XMLoadHalf4) case DXGI_FORMAT_R16G16B16A16_UNORM: - LOAD_SCANLINE( XMUSHORTN4, XMLoadUShortN4 ) + LOAD_SCANLINE(XMUSHORTN4, XMLoadUShortN4) case DXGI_FORMAT_R16G16B16A16_UINT: - LOAD_SCANLINE( XMUSHORT4, XMLoadUShort4 ) + LOAD_SCANLINE(XMUSHORT4, XMLoadUShort4) case DXGI_FORMAT_R16G16B16A16_SNORM: - LOAD_SCANLINE( XMSHORTN4, XMLoadShortN4 ) + LOAD_SCANLINE(XMSHORTN4, XMLoadShortN4) case DXGI_FORMAT_R16G16B16A16_SINT: - LOAD_SCANLINE( XMSHORT4, XMLoadShort4 ) + LOAD_SCANLINE(XMSHORT4, XMLoadShort4) case DXGI_FORMAT_R32G32_FLOAT: - LOAD_SCANLINE2( XMFLOAT2, XMLoadFloat2, g_XMIdentityR3 ) + LOAD_SCANLINE2(XMFLOAT2, XMLoadFloat2, g_XMIdentityR3) case DXGI_FORMAT_R32G32_UINT: - LOAD_SCANLINE2( XMUINT2, XMLoadUInt2, g_XMIdentityR3 ) + LOAD_SCANLINE2(XMUINT2, XMLoadUInt2, g_XMIdentityR3) case DXGI_FORMAT_R32G32_SINT: - LOAD_SCANLINE2( XMINT2, XMLoadSInt2, g_XMIdentityR3 ) + LOAD_SCANLINE2(XMINT2, XMLoadSInt2, g_XMIdentityR3) case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: { - const size_t psize = sizeof(float)+sizeof(uint32_t); - if ( size >= psize ) + const size_t psize = sizeof(float) + sizeof(uint32_t); + if (size >= psize) { const float * sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - psize + 1 ); icount += psize ) + for (size_t icount = 0; icount < (size - psize + 1); icount += psize) { - const uint8_t* ps8 = reinterpret_cast( &sPtr[1] ); - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSet( sPtr[0], static_cast( *ps8 ), 0.f, 1.f ); + const uint8_t* ps8 = reinterpret_cast(&sPtr[1]); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSet(sPtr[0], static_cast(*ps8), 0.f, 1.f); sPtr += 2; } return true; @@ -824,191 +842,191 @@ _Use_decl_annotations_ bool _LoadScanline( XMVECTOR* pDestination, size_t count, return false; case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + { + const size_t psize = sizeof(float) + sizeof(uint32_t); + if (size >= psize) { - const size_t psize = sizeof(float)+sizeof(uint32_t); - if ( size >= psize ) + const float * sPtr = reinterpret_cast(pSource); + for (size_t icount = 0; icount < (size - psize + 1); icount += psize) { - const float * sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - psize + 1 ); icount += psize ) - { - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSet( sPtr[0], 0.f /* typeless component assumed zero */, 0.f, 1.f ); - sPtr += 2; - } - return true; + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSet(sPtr[0], 0.f /* typeless component assumed zero */, 0.f, 1.f); + sPtr += 2; } + return true; } - return false; + } + return false; case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + { + const size_t psize = sizeof(float) + sizeof(uint32_t); + if (size >= psize) { - const size_t psize = sizeof(float)+sizeof(uint32_t); - if ( size >= psize ) + const float * sPtr = reinterpret_cast(pSource); + for (size_t icount = 0; icount < (size - psize + 1); icount += psize) { - const float * sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - psize + 1 ); icount += psize ) - { - const uint8_t* pg8 = reinterpret_cast( &sPtr[1] ); - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSet( 0.f /* typeless component assumed zero */, static_cast( *pg8 ), 0.f, 1.f ); - sPtr += 2; - } - return true; + const uint8_t* pg8 = reinterpret_cast(&sPtr[1]); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSet(0.f /* typeless component assumed zero */, static_cast(*pg8), 0.f, 1.f); + sPtr += 2; } + return true; } - return false; + } + return false; case DXGI_FORMAT_R10G10B10A2_UNORM: - LOAD_SCANLINE( XMUDECN4, XMLoadUDecN4 ); + LOAD_SCANLINE(XMUDECN4, XMLoadUDecN4); case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: - LOAD_SCANLINE( XMUDECN4, XMLoadUDecN4_XR ); + LOAD_SCANLINE(XMUDECN4, XMLoadUDecN4_XR); case DXGI_FORMAT_R10G10B10A2_UINT: - LOAD_SCANLINE( XMUDEC4, XMLoadUDec4 ); + LOAD_SCANLINE(XMUDEC4, XMLoadUDec4); case DXGI_FORMAT_R11G11B10_FLOAT: - LOAD_SCANLINE3( XMFLOAT3PK, XMLoadFloat3PK, g_XMIdentityR3 ); + LOAD_SCANLINE3(XMFLOAT3PK, XMLoadFloat3PK, g_XMIdentityR3); case DXGI_FORMAT_R8G8B8A8_UNORM: case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - LOAD_SCANLINE( XMUBYTEN4, XMLoadUByteN4 ) + LOAD_SCANLINE(XMUBYTEN4, XMLoadUByteN4) case DXGI_FORMAT_R8G8B8A8_UINT: - LOAD_SCANLINE( XMUBYTE4, XMLoadUByte4 ) + LOAD_SCANLINE(XMUBYTE4, XMLoadUByte4) case DXGI_FORMAT_R8G8B8A8_SNORM: - LOAD_SCANLINE( XMBYTEN4, XMLoadByteN4 ) + LOAD_SCANLINE(XMBYTEN4, XMLoadByteN4) case DXGI_FORMAT_R8G8B8A8_SINT: - LOAD_SCANLINE( XMBYTE4, XMLoadByte4 ) + LOAD_SCANLINE(XMBYTE4, XMLoadByte4) case DXGI_FORMAT_R16G16_FLOAT: - LOAD_SCANLINE2( XMHALF2, XMLoadHalf2, g_XMIdentityR3 ) + LOAD_SCANLINE2(XMHALF2, XMLoadHalf2, g_XMIdentityR3) case DXGI_FORMAT_R16G16_UNORM: - LOAD_SCANLINE2( XMUSHORTN2, XMLoadUShortN2, g_XMIdentityR3 ) + LOAD_SCANLINE2(XMUSHORTN2, XMLoadUShortN2, g_XMIdentityR3) case DXGI_FORMAT_R16G16_UINT: - LOAD_SCANLINE2( XMUSHORT2, XMLoadUShort2, g_XMIdentityR3 ) + LOAD_SCANLINE2(XMUSHORT2, XMLoadUShort2, g_XMIdentityR3) case DXGI_FORMAT_R16G16_SNORM: - LOAD_SCANLINE2( XMSHORTN2, XMLoadShortN2, g_XMIdentityR3 ) + LOAD_SCANLINE2(XMSHORTN2, XMLoadShortN2, g_XMIdentityR3) case DXGI_FORMAT_R16G16_SINT: - LOAD_SCANLINE2( XMSHORT2, XMLoadShort2, g_XMIdentityR3 ) + LOAD_SCANLINE2(XMSHORT2, XMLoadShort2, g_XMIdentityR3) case DXGI_FORMAT_D32_FLOAT: case DXGI_FORMAT_R32_FLOAT: - if ( size >= sizeof(float) ) + if (size >= sizeof(float)) { const float* __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(float) + 1 ); icount += sizeof(float) ) + for (size_t icount = 0; icount < (size - sizeof(float) + 1); icount += sizeof(float)) { - XMVECTOR v = XMLoadFloat( sPtr++ ); - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1000 ); + XMVECTOR v = XMLoadFloat(sPtr++); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1000); } return true; } return false; case DXGI_FORMAT_R32_UINT: - if ( size >= sizeof(uint32_t) ) + if (size >= sizeof(uint32_t)) { const uint32_t* __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(uint32_t) + 1 ); icount += sizeof(uint32_t) ) + for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t)) { - XMVECTOR v = XMLoadInt( sPtr++ ); - v = XMConvertVectorUIntToFloat( v, 0 ); - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1000 ); + XMVECTOR v = XMLoadInt(sPtr++); + v = XMConvertVectorUIntToFloat(v, 0); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1000); } return true; } return false; case DXGI_FORMAT_R32_SINT: - if ( size >= sizeof(int32_t) ) + if (size >= sizeof(int32_t)) { const int32_t * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(int32_t) + 1 ); icount += sizeof(int32_t) ) + for (size_t icount = 0; icount < (size - sizeof(int32_t) + 1); icount += sizeof(int32_t)) { - XMVECTOR v = XMLoadInt( reinterpret_cast (sPtr++) ); - v = XMConvertVectorIntToFloat( v, 0 ); - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1000 ); + XMVECTOR v = XMLoadInt(reinterpret_cast (sPtr++)); + v = XMConvertVectorIntToFloat(v, 0); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1000); } return true; } return false; case DXGI_FORMAT_D24_UNORM_S8_UINT: - if ( size >= sizeof(uint32_t) ) + if (size >= sizeof(uint32_t)) { const uint32_t * sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(uint32_t) + 1 ); icount += sizeof(uint32_t) ) + for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t)) { - float d = static_cast( *sPtr & 0xFFFFFF ) / 16777215.f; - float s = static_cast( ( *sPtr & 0xFF000000 ) >> 24 ); + float d = static_cast(*sPtr & 0xFFFFFF) / 16777215.f; + float s = static_cast((*sPtr & 0xFF000000) >> 24); ++sPtr; - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSet( d, s, 0.f, 1.f ); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSet(d, s, 0.f, 1.f); } return true; } return false; case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: - if ( size >= sizeof(uint32_t) ) + if (size >= sizeof(uint32_t)) { const uint32_t * sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(uint32_t) + 1 ); icount += sizeof(uint32_t) ) + for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t)) { - float r = static_cast( *sPtr & 0xFFFFFF ) / 16777215.f; + float r = static_cast(*sPtr & 0xFFFFFF) / 16777215.f; ++sPtr; - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSet( r, 0.f /* typeless component assumed zero */, 0.f, 1.f ); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSet(r, 0.f /* typeless component assumed zero */, 0.f, 1.f); } return true; } return false; case DXGI_FORMAT_X24_TYPELESS_G8_UINT: - if ( size >= sizeof(uint32_t) ) + if (size >= sizeof(uint32_t)) { const uint32_t * sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(uint32_t) + 1 ); icount += sizeof(uint32_t) ) + for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t)) { - float g = static_cast( ( *sPtr & 0xFF000000 ) >> 24 ); + float g = static_cast((*sPtr & 0xFF000000) >> 24); ++sPtr; - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSet( 0.f /* typeless component assumed zero */, g, 0.f, 1.f ); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSet(0.f /* typeless component assumed zero */, g, 0.f, 1.f); } return true; } return false; case DXGI_FORMAT_R8G8_UNORM: - LOAD_SCANLINE2( XMUBYTEN2, XMLoadUByteN2, g_XMIdentityR3 ) + LOAD_SCANLINE2(XMUBYTEN2, XMLoadUByteN2, g_XMIdentityR3) case DXGI_FORMAT_R8G8_UINT: - LOAD_SCANLINE2( XMUBYTE2, XMLoadUByte2, g_XMIdentityR3 ) + LOAD_SCANLINE2(XMUBYTE2, XMLoadUByte2, g_XMIdentityR3) case DXGI_FORMAT_R8G8_SNORM: - LOAD_SCANLINE2( XMBYTEN2, XMLoadByteN2, g_XMIdentityR3 ) + LOAD_SCANLINE2(XMBYTEN2, XMLoadByteN2, g_XMIdentityR3) case DXGI_FORMAT_R8G8_SINT: - LOAD_SCANLINE2( XMBYTE2, XMLoadByte2, g_XMIdentityR3 ) + LOAD_SCANLINE2(XMBYTE2, XMLoadByte2, g_XMIdentityR3) case DXGI_FORMAT_R16_FLOAT: - if ( size >= sizeof(HALF) ) + if (size >= sizeof(HALF)) { const HALF * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(HALF) + 1 ); icount += sizeof(HALF) ) + for (size_t icount = 0; icount < (size - sizeof(HALF) + 1); icount += sizeof(HALF)) { - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSet( XMConvertHalfToFloat(*sPtr++), 0.f, 0.f, 1.f ); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSet(XMConvertHalfToFloat(*sPtr++), 0.f, 0.f, 1.f); } return true; } @@ -1016,134 +1034,134 @@ _Use_decl_annotations_ bool _LoadScanline( XMVECTOR* pDestination, size_t count, case DXGI_FORMAT_D16_UNORM: case DXGI_FORMAT_R16_UNORM: - if ( size >= sizeof(uint16_t) ) + if (size >= sizeof(uint16_t)) { const uint16_t* __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(uint16_t) + 1 ); icount += sizeof(uint16_t) ) + for (size_t icount = 0; icount < (size - sizeof(uint16_t) + 1); icount += sizeof(uint16_t)) { - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSet( static_cast(*sPtr++) / 65535.f, 0.f, 0.f, 1.f ); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSet(static_cast(*sPtr++) / 65535.f, 0.f, 0.f, 1.f); } return true; } return false; case DXGI_FORMAT_R16_UINT: - if ( size >= sizeof(uint16_t) ) + if (size >= sizeof(uint16_t)) { const uint16_t * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(uint16_t) + 1 ); icount += sizeof(uint16_t) ) + for (size_t icount = 0; icount < (size - sizeof(uint16_t) + 1); icount += sizeof(uint16_t)) { - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSet( static_cast(*sPtr++), 0.f, 0.f, 1.f ); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSet(static_cast(*sPtr++), 0.f, 0.f, 1.f); } return true; } return false; case DXGI_FORMAT_R16_SNORM: - if ( size >= sizeof(int16_t) ) + if (size >= sizeof(int16_t)) { const int16_t * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(int16_t) + 1 ); icount += sizeof(int16_t) ) + for (size_t icount = 0; icount < (size - sizeof(int16_t) + 1); icount += sizeof(int16_t)) { - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSet( static_cast(*sPtr++) / 32767.f, 0.f, 0.f, 1.f ); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSet(static_cast(*sPtr++) / 32767.f, 0.f, 0.f, 1.f); } return true; } return false; case DXGI_FORMAT_R16_SINT: - if ( size >= sizeof(int16_t) ) + if (size >= sizeof(int16_t)) { const int16_t * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(int16_t) + 1 ); icount += sizeof(int16_t) ) + for (size_t icount = 0; icount < (size - sizeof(int16_t) + 1); icount += sizeof(int16_t)) { - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSet( static_cast(*sPtr++), 0.f, 0.f, 1.f ); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSet(static_cast(*sPtr++), 0.f, 0.f, 1.f); } return true; } return false; case DXGI_FORMAT_R8_UNORM: - if ( size >= sizeof(uint8_t) ) + if (size >= sizeof(uint8_t)) { const uint8_t * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) ) + for (size_t icount = 0; icount < size; icount += sizeof(uint8_t)) { - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSet( static_cast(*sPtr++) / 255.f, 0.f, 0.f, 1.f ); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSet(static_cast(*sPtr++) / 255.f, 0.f, 0.f, 1.f); } return true; } return false; case DXGI_FORMAT_R8_UINT: - if ( size >= sizeof(uint8_t) ) + if (size >= sizeof(uint8_t)) { const uint8_t * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) ) + for (size_t icount = 0; icount < size; icount += sizeof(uint8_t)) { - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSet( static_cast(*sPtr++), 0.f, 0.f, 1.f ); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSet(static_cast(*sPtr++), 0.f, 0.f, 1.f); } return true; } return false; case DXGI_FORMAT_R8_SNORM: - if ( size >= sizeof(int8_t) ) + if (size >= sizeof(int8_t)) { const int8_t * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < size; icount += sizeof(int8_t) ) + for (size_t icount = 0; icount < size; icount += sizeof(int8_t)) { - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSet( static_cast(*sPtr++) / 127.f, 0.f, 0.f, 1.f ); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSet(static_cast(*sPtr++) / 127.f, 0.f, 0.f, 1.f); } return true; } return false; case DXGI_FORMAT_R8_SINT: - if ( size >= sizeof(int8_t) ) + if (size >= sizeof(int8_t)) { const int8_t * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < size; icount += sizeof(int8_t) ) + for (size_t icount = 0; icount < size; icount += sizeof(int8_t)) { - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSet( static_cast(*sPtr++), 0.f, 0.f, 1.f ); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSet(static_cast(*sPtr++), 0.f, 0.f, 1.f); } return true; } return false; case DXGI_FORMAT_A8_UNORM: - if ( size >= sizeof(uint8_t) ) + if (size >= sizeof(uint8_t)) { const uint8_t * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) ) + for (size_t icount = 0; icount < size; icount += sizeof(uint8_t)) { - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSet( 0.f, 0.f, 0.f, static_cast(*sPtr++) / 255.f ); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSet(0.f, 0.f, 0.f, static_cast(*sPtr++) / 255.f); } return true; } return false; case DXGI_FORMAT_R1_UNORM: - if ( size >= sizeof(uint8_t) ) + if (size >= sizeof(uint8_t)) { const uint8_t * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) ) + for (size_t icount = 0; icount < size; icount += sizeof(uint8_t)) { - for( size_t bcount = 8; bcount > 0; --bcount ) + for (size_t bcount = 8; bcount > 0; --bcount) { - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSet( (((*sPtr >> (bcount-1)) & 0x1) ? 1.f : 0.f), 0.f, 0.f, 1.f ); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSet((((*sPtr >> (bcount - 1)) & 0x1) ? 1.f : 0.f), 0.f, 0.f, 1.f); } - + ++sPtr; } return true; @@ -1151,71 +1169,71 @@ _Use_decl_annotations_ bool _LoadScanline( XMVECTOR* pDestination, size_t count, return false; case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: - LOAD_SCANLINE3( XMFLOAT3SE, XMLoadFloat3SE, g_XMIdentityR3 ) + LOAD_SCANLINE3(XMFLOAT3SE, XMLoadFloat3SE, g_XMIdentityR3) case DXGI_FORMAT_R8G8_B8G8_UNORM: - if ( size >= sizeof(XMUBYTEN4) ) + if (size >= sizeof(XMUBYTEN4)) { const XMUBYTEN4 * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(XMUBYTEN4) + 1 ); icount += sizeof(XMUBYTEN4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4)) { - XMVECTOR v = XMLoadUByteN4( sPtr++ ); - XMVECTOR v1 = XMVectorSwizzle<0, 3, 2, 1>( v ); - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1110 ); - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v1, g_XMSelect1110 ); + XMVECTOR v = XMLoadUByteN4(sPtr++); + XMVECTOR v1 = XMVectorSwizzle<0, 3, 2, 1>(v); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1110); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v1, g_XMSelect1110); } return true; } return false; case DXGI_FORMAT_G8R8_G8B8_UNORM: - if ( size >= sizeof(XMUBYTEN4) ) + if (size >= sizeof(XMUBYTEN4)) { const XMUBYTEN4 * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(XMUBYTEN4) + 1 ); icount += sizeof(XMUBYTEN4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4)) { - XMVECTOR v = XMLoadUByteN4( sPtr++ ); - XMVECTOR v0 = XMVectorSwizzle<1, 0, 3, 2>( v ); - XMVECTOR v1 = XMVectorSwizzle<1, 2, 3, 0>( v ); - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v0, g_XMSelect1110 ); - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v1, g_XMSelect1110 ); + XMVECTOR v = XMLoadUByteN4(sPtr++); + XMVECTOR v0 = XMVectorSwizzle<1, 0, 3, 2>(v); + XMVECTOR v1 = XMVectorSwizzle<1, 2, 3, 0>(v); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v0, g_XMSelect1110); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v1, g_XMSelect1110); } return true; } return false; case DXGI_FORMAT_B5G6R5_UNORM: - if ( size >= sizeof(XMU565) ) + if (size >= sizeof(XMU565)) { - static const XMVECTORF32 s_Scale = { 1.f/31.f, 1.f/63.f, 1.f/31.f, 1.f }; + static const XMVECTORF32 s_Scale = { 1.f / 31.f, 1.f / 63.f, 1.f / 31.f, 1.f }; const XMU565 * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(XMU565) + 1 ); icount += sizeof(XMU565) ) + for (size_t icount = 0; icount < (size - sizeof(XMU565) + 1); icount += sizeof(XMU565)) { - XMVECTOR v = XMLoadU565( sPtr++ ); - v = XMVectorMultiply( v, s_Scale ); - v = XMVectorSwizzle<2, 1, 0, 3>( v ); - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1110 ); + XMVECTOR v = XMLoadU565(sPtr++); + v = XMVectorMultiply(v, s_Scale); + v = XMVectorSwizzle<2, 1, 0, 3>(v); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1110); } return true; } return false; case DXGI_FORMAT_B5G5R5A1_UNORM: - if ( size >= sizeof(XMU555) ) + if (size >= sizeof(XMU555)) { - static const XMVECTORF32 s_Scale = { 1.f/31.f, 1.f/31.f, 1.f/31.f, 1.f }; + static const XMVECTORF32 s_Scale = { 1.f / 31.f, 1.f / 31.f, 1.f / 31.f, 1.f }; const XMU555 * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(XMU555) + 1 ); icount += sizeof(XMU555) ) + for (size_t icount = 0; icount < (size - sizeof(XMU555) + 1); icount += sizeof(XMU555)) { - XMVECTOR v = XMLoadU555( sPtr++ ); - v = XMVectorMultiply( v, s_Scale ); - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>( v ); + XMVECTOR v = XMLoadU555(sPtr++); + v = XMVectorMultiply(v, s_Scale); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>(v); } return true; } @@ -1223,14 +1241,14 @@ _Use_decl_annotations_ bool _LoadScanline( XMVECTOR* pDestination, size_t count, case DXGI_FORMAT_B8G8R8A8_UNORM: case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: - if ( size >= sizeof(XMUBYTEN4) ) + if (size >= sizeof(XMUBYTEN4)) { const XMUBYTEN4 * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(XMUBYTEN4) + 1 ); icount += sizeof(XMUBYTEN4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4)) { - XMVECTOR v = XMLoadUByteN4( sPtr++ ); - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>( v ); + XMVECTOR v = XMLoadUByteN4(sPtr++); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>(v); } return true; } @@ -1238,25 +1256,25 @@ _Use_decl_annotations_ bool _LoadScanline( XMVECTOR* pDestination, size_t count, case DXGI_FORMAT_B8G8R8X8_UNORM: case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: - if ( size >= sizeof(XMUBYTEN4) ) + if (size >= sizeof(XMUBYTEN4)) { const XMUBYTEN4 * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(XMUBYTEN4) + 1 ); icount += sizeof(XMUBYTEN4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4)) { - XMVECTOR v = XMLoadUByteN4( sPtr++ ); - v = XMVectorSwizzle<2, 1, 0, 3>( v ); - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1110 ); + XMVECTOR v = XMLoadUByteN4(sPtr++); + v = XMVectorSwizzle<2, 1, 0, 3>(v); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1110); } return true; } return false; case DXGI_FORMAT_AYUV: - if ( size >= sizeof(XMUBYTEN4) ) + if (size >= sizeof(XMUBYTEN4)) { const XMUBYTEN4 * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(XMUBYTEN4) + 1 ); icount += sizeof(XMUBYTEN4) ) + 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; @@ -1274,25 +1292,25 @@ _Use_decl_annotations_ bool _LoadScanline( XMVECTOR* pDestination, size_t count, // G = 1.1644Y’ - 0.3917Cb’ - 0.8128Cr’ // B = 1.1644Y’ + 2.0172Cb’ - int r = (298 * y + 409 * v + 128) >> 8; + 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; + 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 ) ); + 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) ) + if (size >= sizeof(XMUDECN4)) { const XMUDECN4 * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(XMUDECN4) + 1 ); icount += sizeof(XMUDECN4) ) + 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; @@ -1310,25 +1328,25 @@ _Use_decl_annotations_ bool _LoadScanline( XMVECTOR* pDestination, size_t count, // 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 ); + 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 ) ); + 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) ) + if (size >= sizeof(XMUSHORTN4)) { const XMUSHORTN4 * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(XMUSHORTN4) + 1 ); icount += sizeof(XMUSHORTN4) ) + 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; @@ -1346,52 +1364,52 @@ _Use_decl_annotations_ bool _LoadScanline( XMVECTOR* pDestination, size_t count, // 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 ); + 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 ); + 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) ) + if (size >= sizeof(XMUBYTEN4)) { const XMUBYTEN4 * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(XMUBYTEN4) + 1 ); icount += sizeof(XMUBYTEN4) ) + 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 u = int(sPtr->y) - 128; int y1 = int(sPtr->z) - 16; - int v = int(sPtr->w) - 128; + int v = int(sPtr->w) - 128; ++sPtr; // See AYUV - int r = (298 * y0 + 409 * v + 128) >> 8; + 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; + 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; + 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; + 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 ); + 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; } @@ -1399,90 +1417,90 @@ _Use_decl_annotations_ bool _LoadScanline( XMVECTOR* pDestination, size_t count, case DXGI_FORMAT_Y210: // Same as Y216 with least significant 6 bits set to zero - if ( size >= sizeof(XMUSHORTN4) ) + if (size >= sizeof(XMUSHORTN4)) { const XMUSHORTN4 * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(XMUSHORTN4) + 1 ); icount += sizeof(XMUSHORTN4) ) + 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 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; + 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 ); + 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 ); + 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 ); + 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 ); + 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) ) + if (size >= sizeof(XMUSHORTN4)) { const XMUSHORTN4 * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(XMUSHORTN4) + 1 ); icount += sizeof(XMUSHORTN4) ) + 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 u = int64_t(sPtr->y) - 32768; int64_t y1 = int64_t(sPtr->z) - 4096; - int64_t v = int64_t(sPtr->w) - 32768; + 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 ); + 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 ); + 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 ); + 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 ); + 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) ) + if (size >= sizeof(XMUNIBBLE4)) { - static const XMVECTORF32 s_Scale = { 1.f/15.f, 1.f/15.f, 1.f/15.f, 1.f/15.f }; + static const XMVECTORF32 s_Scale = { 1.f / 15.f, 1.f / 15.f, 1.f / 15.f, 1.f / 15.f }; const XMUNIBBLE4 * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(XMUNIBBLE4) + 1 ); icount += sizeof(XMUNIBBLE4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUNIBBLE4) + 1); icount += sizeof(XMUNIBBLE4)) { - XMVECTOR v = XMLoadUNibble4( sPtr++ ); - v = XMVectorMultiply( v, s_Scale ); - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>( v ); + XMVECTOR v = XMLoadUNibble4(sPtr++); + v = XMVectorMultiply(v, s_Scale); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>(v); } return true; } @@ -1490,12 +1508,12 @@ _Use_decl_annotations_ bool _LoadScanline( XMVECTOR* pDestination, size_t count, case XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT: // Xbox One specific 7e3 format - if ( size >= sizeof(XMUDECN4) ) + if (size >= sizeof(XMUDECN4)) { const XMUDECN4 * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(XMUDECN4) + 1 ); icount += sizeof(XMUDECN4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUDECN4) + 1); icount += sizeof(XMUDECN4)) { - if ( dPtr >= ePtr ) break; + if (dPtr >= ePtr) break; XMVECTORF32 vResult = { FloatFrom7e3(sPtr->x), @@ -1514,12 +1532,12 @@ _Use_decl_annotations_ bool _LoadScanline( XMVECTOR* pDestination, size_t count, case XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT: // Xbox One specific 6e4 format - if ( size >= sizeof(XMUDECN4) ) + if (size >= sizeof(XMUDECN4)) { const XMUDECN4 * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(XMUDECN4) + 1 ); icount += sizeof(XMUDECN4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUDECN4) + 1); icount += sizeof(XMUDECN4)) { - if ( dPtr >= ePtr ) break; + if (dPtr >= ePtr) break; XMVECTORF32 vResult = { FloatFrom6e4(sPtr->x), @@ -1538,28 +1556,28 @@ _Use_decl_annotations_ bool _LoadScanline( XMVECTOR* pDestination, size_t count, case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM: // Xbox One specific format - LOAD_SCANLINE( XMXDECN4, XMLoadXDecN4 ); + LOAD_SCANLINE(XMXDECN4, XMLoadXDecN4); case XBOX_DXGI_FORMAT_R4G4_UNORM: // Xbox One specific format - if ( size >= sizeof(uint8_t) ) + if (size >= sizeof(uint8_t)) { - static const XMVECTORF32 s_Scale = { 1.f/15.f, 1.f/15.f, 0.f, 0.f }; + static const XMVECTORF32 s_Scale = { 1.f / 15.f, 1.f / 15.f, 0.f, 0.f }; const uint8_t * __restrict sPtr = reinterpret_cast(pSource); - for( size_t icount = 0; icount < ( size - sizeof(uint8_t) + 1 ); icount += sizeof(uint8_t) ) + for (size_t icount = 0; icount < (size - sizeof(uint8_t) + 1); icount += sizeof(uint8_t)) { XMUNIBBLE4 nibble; - nibble.v = static_cast( *sPtr++ ); - XMVECTOR v = XMLoadUNibble4( &nibble ); - v = XMVectorMultiply( v, s_Scale ); - if ( dPtr >= ePtr ) break; - *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1100 ); + nibble.v = static_cast(*sPtr++); + XMVECTOR v = XMLoadUNibble4(&nibble); + v = XMVectorMultiply(v, s_Scale); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1100); } return true; } return false; - // We don't support the planar or palettized formats + // We don't support the planar or palettized formats default: return false; @@ -1588,89 +1606,94 @@ _Use_decl_annotations_ bool _LoadScanline( XMVECTOR* pDestination, size_t count, return false; _Use_decl_annotations_ -bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, - const XMVECTOR* pSource, size_t count, float threshold ) +bool DirectX::_StoreScanline( + void* pDestination, + size_t size, + DXGI_FORMAT format, + const XMVECTOR* pSource, + size_t count, + float threshold) { - assert( pDestination && size > 0 ); - assert( pSource && count > 0 && (((uintptr_t)pSource & 0xF) == 0) ); - assert( IsValid(format) && !IsTypeless(format) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format) ); + assert(pDestination && size > 0); + assert(pSource && count > 0 && (((uintptr_t)pSource & 0xF) == 0)); + assert(IsValid(format) && !IsTypeless(format) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format)); const XMVECTOR* __restrict sPtr = pSource; - if ( !sPtr ) + if (!sPtr) return false; const XMVECTOR* ePtr = pSource + count; - switch( static_cast(format) ) + switch (static_cast(format)) { case DXGI_FORMAT_R32G32B32A32_FLOAT: - STORE_SCANLINE( XMFLOAT4, XMStoreFloat4 ) + STORE_SCANLINE(XMFLOAT4, XMStoreFloat4) case DXGI_FORMAT_R32G32B32A32_UINT: - STORE_SCANLINE( XMUINT4, XMStoreUInt4 ) + STORE_SCANLINE(XMUINT4, XMStoreUInt4) case DXGI_FORMAT_R32G32B32A32_SINT: - STORE_SCANLINE( XMINT4, XMStoreSInt4 ) + STORE_SCANLINE(XMINT4, XMStoreSInt4) case DXGI_FORMAT_R32G32B32_FLOAT: - STORE_SCANLINE( XMFLOAT3, XMStoreFloat3 ) + STORE_SCANLINE(XMFLOAT3, XMStoreFloat3) case DXGI_FORMAT_R32G32B32_UINT: - STORE_SCANLINE( XMUINT3, XMStoreUInt3 ) + STORE_SCANLINE(XMUINT3, XMStoreUInt3) case DXGI_FORMAT_R32G32B32_SINT: - STORE_SCANLINE( XMINT3, XMStoreSInt3 ) + STORE_SCANLINE(XMINT3, XMStoreSInt3) case DXGI_FORMAT_R16G16B16A16_FLOAT: - if ( size >= sizeof(XMHALF4) ) + if (size >= sizeof(XMHALF4)) { XMHALF4* __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(XMHALF4) + 1 ); icount += sizeof(XMHALF4) ) + for (size_t icount = 0; icount < (size - sizeof(XMHALF4) + 1); icount += sizeof(XMHALF4)) { - if ( sPtr >= ePtr ) break; + if (sPtr >= ePtr) break; XMVECTOR v = *sPtr++; - v = XMVectorClamp( v, g_HalfMin, g_HalfMax ); - XMStoreHalf4( dPtr++, v ); + v = XMVectorClamp(v, g_HalfMin, g_HalfMax); + XMStoreHalf4(dPtr++, v); } return true; } return false; case DXGI_FORMAT_R16G16B16A16_UNORM: - STORE_SCANLINE( XMUSHORTN4, XMStoreUShortN4 ) + STORE_SCANLINE(XMUSHORTN4, XMStoreUShortN4) case DXGI_FORMAT_R16G16B16A16_UINT: - STORE_SCANLINE( XMUSHORT4, XMStoreUShort4 ) + STORE_SCANLINE(XMUSHORT4, XMStoreUShort4) case DXGI_FORMAT_R16G16B16A16_SNORM: - STORE_SCANLINE( XMSHORTN4, XMStoreShortN4 ) + STORE_SCANLINE(XMSHORTN4, XMStoreShortN4) case DXGI_FORMAT_R16G16B16A16_SINT: - STORE_SCANLINE( XMSHORT4, XMStoreShort4 ) + STORE_SCANLINE(XMSHORT4, XMStoreShort4) case DXGI_FORMAT_R32G32_FLOAT: - STORE_SCANLINE( XMFLOAT2, XMStoreFloat2 ) + STORE_SCANLINE(XMFLOAT2, XMStoreFloat2) case DXGI_FORMAT_R32G32_UINT: - STORE_SCANLINE( XMUINT2, XMStoreUInt2 ) + STORE_SCANLINE(XMUINT2, XMStoreUInt2) case DXGI_FORMAT_R32G32_SINT: - STORE_SCANLINE( XMINT2, XMStoreSInt2 ) + STORE_SCANLINE(XMINT2, XMStoreSInt2) case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: { - const size_t psize = sizeof(float)+sizeof(uint32_t); - if ( size >= psize ) + const size_t psize = sizeof(float) + sizeof(uint32_t); + if (size >= psize) { float *dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - psize + 1 ); icount += psize ) + for (size_t icount = 0; icount < (size - psize + 1); icount += psize) { - if ( sPtr >= ePtr ) break; + if (sPtr >= ePtr) break; XMFLOAT4 f; - XMStoreFloat4( &f, *sPtr++ ); + XMStoreFloat4(&f, *sPtr++); dPtr[0] = f.x; - uint8_t* ps8 = reinterpret_cast( &dPtr[1] ); - ps8[0] = static_cast( std::min( 255.f, std::max( 0.f, f.y ) ) ); + uint8_t* ps8 = reinterpret_cast(&dPtr[1]); + ps8[0] = static_cast(std::min(255.f, std::max(0.f, f.y))); ps8[1] = ps8[2] = ps8[3] = 0; dPtr += 2; } @@ -1680,149 +1703,149 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, return false; case DXGI_FORMAT_R10G10B10A2_UNORM: - STORE_SCANLINE( XMUDECN4, XMStoreUDecN4 ); + STORE_SCANLINE(XMUDECN4, XMStoreUDecN4); case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: - STORE_SCANLINE( XMUDECN4, XMStoreUDecN4_XR ); + STORE_SCANLINE(XMUDECN4, XMStoreUDecN4_XR); case DXGI_FORMAT_R10G10B10A2_UINT: - STORE_SCANLINE( XMUDEC4, XMStoreUDec4 ); + STORE_SCANLINE(XMUDEC4, XMStoreUDec4); case DXGI_FORMAT_R11G11B10_FLOAT: - STORE_SCANLINE( XMFLOAT3PK, XMStoreFloat3PK ); + STORE_SCANLINE(XMFLOAT3PK, XMStoreFloat3PK); case DXGI_FORMAT_R8G8B8A8_UNORM: case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - if ( size >= sizeof(XMUBYTEN4) ) + if (size >= sizeof(XMUBYTEN4)) { XMUBYTEN4 * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(XMUBYTEN4) + 1 ); icount += sizeof(XMUBYTEN4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4)) { - if ( sPtr >= ePtr ) break; - XMVECTOR v = XMVectorAdd( *sPtr++, g_8BitBias ); - XMStoreUByteN4( dPtr++, v ); + if (sPtr >= ePtr) break; + XMVECTOR v = XMVectorAdd(*sPtr++, g_8BitBias); + XMStoreUByteN4(dPtr++, v); } return true; } return false; case DXGI_FORMAT_R8G8B8A8_UINT: - STORE_SCANLINE( XMUBYTE4, XMStoreUByte4 ) + STORE_SCANLINE(XMUBYTE4, XMStoreUByte4) case DXGI_FORMAT_R8G8B8A8_SNORM: - STORE_SCANLINE( XMBYTEN4, XMStoreByteN4 ) + STORE_SCANLINE(XMBYTEN4, XMStoreByteN4) case DXGI_FORMAT_R8G8B8A8_SINT: - STORE_SCANLINE( XMBYTE4, XMStoreByte4 ) + STORE_SCANLINE(XMBYTE4, XMStoreByte4) case DXGI_FORMAT_R16G16_FLOAT: - if ( size >= sizeof(XMHALF2) ) + if (size >= sizeof(XMHALF2)) { XMHALF2* __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(XMHALF2) + 1 ); icount += sizeof(XMHALF2) ) + for (size_t icount = 0; icount < (size - sizeof(XMHALF2) + 1); icount += sizeof(XMHALF2)) { - if ( sPtr >= ePtr ) break; + if (sPtr >= ePtr) break; XMVECTOR v = *sPtr++; - v = XMVectorClamp( v, g_HalfMin, g_HalfMax ); - XMStoreHalf2( dPtr++, v ); + v = XMVectorClamp(v, g_HalfMin, g_HalfMax); + XMStoreHalf2(dPtr++, v); } return true; } return false; case DXGI_FORMAT_R16G16_UNORM: - STORE_SCANLINE( XMUSHORTN2, XMStoreUShortN2 ) + STORE_SCANLINE(XMUSHORTN2, XMStoreUShortN2) case DXGI_FORMAT_R16G16_UINT: - STORE_SCANLINE( XMUSHORT2, XMStoreUShort2 ) + STORE_SCANLINE(XMUSHORT2, XMStoreUShort2) case DXGI_FORMAT_R16G16_SNORM: - STORE_SCANLINE( XMSHORTN2, XMStoreShortN2 ) + STORE_SCANLINE(XMSHORTN2, XMStoreShortN2) case DXGI_FORMAT_R16G16_SINT: - STORE_SCANLINE( XMSHORT2, XMStoreShort2 ) + STORE_SCANLINE(XMSHORT2, XMStoreShort2) case DXGI_FORMAT_D32_FLOAT: case DXGI_FORMAT_R32_FLOAT: - if ( size >= sizeof(float) ) + if (size >= sizeof(float)) { float * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(float) + 1 ); icount += sizeof(float) ) + for (size_t icount = 0; icount < (size - sizeof(float) + 1); icount += sizeof(float)) { - if ( sPtr >= ePtr ) break; - XMStoreFloat( dPtr++, *(sPtr++) ); + if (sPtr >= ePtr) break; + XMStoreFloat(dPtr++, *(sPtr++)); } return true; } return false; case DXGI_FORMAT_R32_UINT: - if ( size >= sizeof(uint32_t) ) + if (size >= sizeof(uint32_t)) { uint32_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(uint32_t) + 1 ); icount += sizeof(uint32_t) ) + for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t)) { - if ( sPtr >= ePtr ) break; - XMVECTOR v = XMConvertVectorFloatToUInt( *(sPtr++), 0 ); - XMStoreInt( dPtr++, v ); + if (sPtr >= ePtr) break; + XMVECTOR v = XMConvertVectorFloatToUInt(*(sPtr++), 0); + XMStoreInt(dPtr++, v); } return true; } return false; case DXGI_FORMAT_R32_SINT: - if ( size >= sizeof(int32_t) ) + if (size >= sizeof(int32_t)) { uint32_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(int32_t) + 1 ); icount += sizeof(int32_t) ) + for (size_t icount = 0; icount < (size - sizeof(int32_t) + 1); icount += sizeof(int32_t)) { - if ( sPtr >= ePtr ) break; - XMVECTOR v = XMConvertVectorFloatToInt( *(sPtr++), 0 ); - XMStoreInt( dPtr++, v ); + if (sPtr >= ePtr) break; + XMVECTOR v = XMConvertVectorFloatToInt(*(sPtr++), 0); + XMStoreInt(dPtr++, v); } return true; } return false; case DXGI_FORMAT_D24_UNORM_S8_UINT: - if ( size >= sizeof(uint32_t) ) + if (size >= sizeof(uint32_t)) { static const XMVECTORF32 clamp = { 1.f, 255.f, 0.f, 0.f }; XMVECTOR zero = XMVectorZero(); uint32_t *dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(uint32_t) + 1 ); icount += sizeof(uint32_t) ) + for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t)) { - if ( sPtr >= ePtr ) break; + if (sPtr >= ePtr) break; XMFLOAT4 f; - XMStoreFloat4( &f, XMVectorClamp( *sPtr++, zero, clamp ) ); - *dPtr++ = (static_cast( f.x * 16777215.f ) & 0xFFFFFF) - | ((static_cast( f.y ) & 0xFF) << 24); + XMStoreFloat4(&f, XMVectorClamp(*sPtr++, zero, clamp)); + *dPtr++ = (static_cast(f.x * 16777215.f) & 0xFFFFFF) + | ((static_cast(f.y) & 0xFF) << 24); } return true; } return false; case DXGI_FORMAT_R8G8_UNORM: - STORE_SCANLINE( XMUBYTEN2, XMStoreUByteN2 ) + STORE_SCANLINE(XMUBYTEN2, XMStoreUByteN2) case DXGI_FORMAT_R8G8_UINT: - STORE_SCANLINE( XMUBYTE2, XMStoreUByte2 ) + STORE_SCANLINE(XMUBYTE2, XMStoreUByte2) case DXGI_FORMAT_R8G8_SNORM: - STORE_SCANLINE( XMBYTEN2, XMStoreByteN2 ) + STORE_SCANLINE(XMBYTEN2, XMStoreByteN2) case DXGI_FORMAT_R8G8_SINT: - STORE_SCANLINE( XMBYTE2, XMStoreByte2 ) + STORE_SCANLINE(XMBYTE2, XMStoreByte2) case DXGI_FORMAT_R16_FLOAT: - if ( size >= sizeof(HALF) ) + if (size >= sizeof(HALF)) { HALF * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(HALF) + 1 ); icount += sizeof(HALF) ) + for (size_t icount = 0; icount < (size - sizeof(HALF) + 1); icount += sizeof(HALF)) { - if ( sPtr >= ePtr ) break; - float v = XMVectorGetX( *sPtr++ ); - v = std::max( std::min( v, 65504.f ), -65504.f ); + if (sPtr >= ePtr) break; + float v = XMVectorGetX(*sPtr++); + v = std::max(std::min(v, 65504.f), -65504.f); *(dPtr++) = XMConvertFloatToHalf(v); } return true; @@ -1831,29 +1854,29 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, case DXGI_FORMAT_D16_UNORM: case DXGI_FORMAT_R16_UNORM: - if ( size >= sizeof(uint16_t) ) + if (size >= sizeof(uint16_t)) { uint16_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(uint16_t) + 1 ); icount += sizeof(uint16_t) ) + for (size_t icount = 0; icount < (size - sizeof(uint16_t) + 1); icount += sizeof(uint16_t)) { - if ( sPtr >= ePtr ) break; - float v = XMVectorGetX( *sPtr++ ); - v = std::max( std::min( v, 1.f ), 0.f ); - *(dPtr++) = static_cast( v*65535.f + 0.5f ); + if (sPtr >= ePtr) break; + float v = XMVectorGetX(*sPtr++); + v = std::max(std::min(v, 1.f), 0.f); + *(dPtr++) = static_cast(v*65535.f + 0.5f); } return true; } return false; case DXGI_FORMAT_R16_UINT: - if ( size >= sizeof(uint16_t) ) + if (size >= sizeof(uint16_t)) { uint16_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(uint16_t) + 1 ); icount += sizeof(uint16_t) ) + for (size_t icount = 0; icount < (size - sizeof(uint16_t) + 1); icount += sizeof(uint16_t)) { - if ( sPtr >= ePtr ) break; - float v = XMVectorGetX( *sPtr++ ); - v = std::max( std::min( v, 65535.f ), 0.f ); + if (sPtr >= ePtr) break; + float v = XMVectorGetX(*sPtr++); + v = std::max(std::min(v, 65535.f), 0.f); *(dPtr++) = static_cast(v); } return true; @@ -1861,29 +1884,29 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, return false; case DXGI_FORMAT_R16_SNORM: - if ( size >= sizeof(int16_t) ) + if (size >= sizeof(int16_t)) { int16_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(int16_t) + 1 ); icount += sizeof(int16_t) ) + for (size_t icount = 0; icount < (size - sizeof(int16_t) + 1); icount += sizeof(int16_t)) { - if ( sPtr >= ePtr ) break; - float v = XMVectorGetX( *sPtr++ ); - v = std::max( std::min( v, 1.f ), -1.f ); - *(dPtr++) = static_cast( v * 32767.f ); + if (sPtr >= ePtr) break; + float v = XMVectorGetX(*sPtr++); + v = std::max(std::min(v, 1.f), -1.f); + *(dPtr++) = static_cast(v * 32767.f); } return true; } return false; case DXGI_FORMAT_R16_SINT: - if ( size >= sizeof(int16_t) ) + if (size >= sizeof(int16_t)) { int16_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(int16_t) + 1 ); icount += sizeof(int16_t) ) + for (size_t icount = 0; icount < (size - sizeof(int16_t) + 1); icount += sizeof(int16_t)) { - if ( sPtr >= ePtr ) break; - float v = XMVectorGetX( *sPtr++ ); - v = std::max( std::min( v, 32767.f ), -32767.f ); + if (sPtr >= ePtr) break; + float v = XMVectorGetX(*sPtr++); + v = std::max(std::min(v, 32767.f), -32767.f); *(dPtr++) = static_cast(v); } return true; @@ -1891,29 +1914,29 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, return false; case DXGI_FORMAT_R8_UNORM: - if ( size >= sizeof(uint8_t) ) + if (size >= sizeof(uint8_t)) { uint8_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) ) + for (size_t icount = 0; icount < size; icount += sizeof(uint8_t)) { - if ( sPtr >= ePtr ) break; - float v = XMVectorGetX( *sPtr++ ); - v = std::max( std::min( v, 1.f ), 0.f ); - *(dPtr++) = static_cast( v * 255.f ); + if (sPtr >= ePtr) break; + float v = XMVectorGetX(*sPtr++); + v = std::max(std::min(v, 1.f), 0.f); + *(dPtr++) = static_cast(v * 255.f); } return true; } return false; case DXGI_FORMAT_R8_UINT: - if ( size >= sizeof(uint8_t) ) + if (size >= sizeof(uint8_t)) { uint8_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) ) + for (size_t icount = 0; icount < size; icount += sizeof(uint8_t)) { - if ( sPtr >= ePtr ) break; - float v = XMVectorGetX( *sPtr++ ); - v = std::max( std::min( v, 255.f ), 0.f ); + if (sPtr >= ePtr) break; + float v = XMVectorGetX(*sPtr++); + v = std::max(std::min(v, 255.f), 0.f); *(dPtr++) = static_cast(v); } return true; @@ -1921,67 +1944,67 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, return false; case DXGI_FORMAT_R8_SNORM: - if ( size >= sizeof(int8_t) ) + if (size >= sizeof(int8_t)) { int8_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < size; icount += sizeof(int8_t) ) + for (size_t icount = 0; icount < size; icount += sizeof(int8_t)) { - if ( sPtr >= ePtr ) break; - float v = XMVectorGetX( *sPtr++ ); - v = std::max( std::min( v, 1.f ), -1.f ); - *(dPtr++) = static_cast( v * 127.f ); + if (sPtr >= ePtr) break; + float v = XMVectorGetX(*sPtr++); + v = std::max(std::min(v, 1.f), -1.f); + *(dPtr++) = static_cast(v * 127.f); } return true; } return false; case DXGI_FORMAT_R8_SINT: - if ( size >= sizeof(int8_t) ) + if (size >= sizeof(int8_t)) { int8_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < size; icount += sizeof(int8_t) ) + for (size_t icount = 0; icount < size; icount += sizeof(int8_t)) { - if ( sPtr >= ePtr ) break; - float v = XMVectorGetX( *sPtr++ ); - v = std::max( std::min( v, 127.f ), -127.f ); - *(dPtr++) = static_cast( v ); + if (sPtr >= ePtr) break; + float v = XMVectorGetX(*sPtr++); + v = std::max(std::min(v, 127.f), -127.f); + *(dPtr++) = static_cast(v); } return true; } return false; case DXGI_FORMAT_A8_UNORM: - if ( size >= sizeof(uint8_t) ) + if (size >= sizeof(uint8_t)) { uint8_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) ) + for (size_t icount = 0; icount < size; icount += sizeof(uint8_t)) { - if ( sPtr >= ePtr ) break; - float v = XMVectorGetW( *sPtr++ ); - v = std::max( std::min( v, 1.f ), 0.f ); - *(dPtr++) = static_cast( v * 255.f); + if (sPtr >= ePtr) break; + float v = XMVectorGetW(*sPtr++); + v = std::max(std::min(v, 1.f), 0.f); + *(dPtr++) = static_cast(v * 255.f); } return true; } return false; case DXGI_FORMAT_R1_UNORM: - if ( size >= sizeof(uint8_t) ) + if (size >= sizeof(uint8_t)) { uint8_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) ) + for (size_t icount = 0; icount < size; icount += sizeof(uint8_t)) { uint8_t pixels = 0; - for( size_t bcount = 8; bcount > 0; --bcount ) + for (size_t bcount = 8; bcount > 0; --bcount) { - if ( sPtr >= ePtr ) break; - float v = XMVectorGetX( *sPtr++ ); + if (sPtr >= ePtr) break; + float v = XMVectorGetX(*sPtr++); // Absolute thresholding generally doesn't give good results for all images // Picking the 'right' threshold automatically requires whole-image analysis - if ( v > 0.25f ) - pixels |= 1 << (bcount-1); + if (v > 0.25f) + pixels |= 1 << (bcount - 1); } *(dPtr++) = pixels; } @@ -1990,72 +2013,72 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, return false; case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: - STORE_SCANLINE( XMFLOAT3SE, StoreFloat3SE ) + STORE_SCANLINE(XMFLOAT3SE, StoreFloat3SE) case DXGI_FORMAT_R8G8_B8G8_UNORM: - if ( size >= sizeof(XMUBYTEN4) ) + if (size >= sizeof(XMUBYTEN4)) { XMUBYTEN4 * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(XMUBYTEN4) + 1 ); icount += sizeof(XMUBYTEN4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4)) { - if ( sPtr >= ePtr ) break; + if (sPtr >= ePtr) break; XMVECTOR v0 = *sPtr++; - XMVECTOR v1 = (sPtr < ePtr) ? XMVectorSplatY( *sPtr++ ) : XMVectorZero(); - XMVECTOR v = XMVectorSelect( v1, v0, g_XMSelect1110 ); - v = XMVectorAdd( v, g_8BitBias ); - XMStoreUByteN4( dPtr++, v ); + XMVECTOR v1 = (sPtr < ePtr) ? XMVectorSplatY(*sPtr++) : XMVectorZero(); + XMVECTOR v = XMVectorSelect(v1, v0, g_XMSelect1110); + v = XMVectorAdd(v, g_8BitBias); + XMStoreUByteN4(dPtr++, v); } return true; } return false; case DXGI_FORMAT_G8R8_G8B8_UNORM: - if ( size >= sizeof(XMUBYTEN4) ) + if (size >= sizeof(XMUBYTEN4)) { - static XMVECTORU32 select1101 = {XM_SELECT_1, XM_SELECT_1, XM_SELECT_0, XM_SELECT_1}; + static XMVECTORU32 select1101 = { XM_SELECT_1, XM_SELECT_1, XM_SELECT_0, XM_SELECT_1 }; XMUBYTEN4 * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(XMUBYTEN4) + 1 ); icount += sizeof(XMUBYTEN4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4)) { - if ( sPtr >= ePtr ) break; - XMVECTOR v0 = XMVectorSwizzle<1, 0, 3, 2>( *sPtr++ ); - XMVECTOR v1 = (sPtr < ePtr) ? XMVectorSplatY( *sPtr++ ) : XMVectorZero(); - XMVECTOR v = XMVectorSelect( v1, v0, select1101 ); - v = XMVectorAdd( v, g_8BitBias ); - XMStoreUByteN4( dPtr++, v ); + if (sPtr >= ePtr) break; + XMVECTOR v0 = XMVectorSwizzle<1, 0, 3, 2>(*sPtr++); + XMVECTOR v1 = (sPtr < ePtr) ? XMVectorSplatY(*sPtr++) : XMVectorZero(); + XMVECTOR v = XMVectorSelect(v1, v0, select1101); + v = XMVectorAdd(v, g_8BitBias); + XMStoreUByteN4(dPtr++, v); } return true; } return false; case DXGI_FORMAT_B5G6R5_UNORM: - if ( size >= sizeof(XMU565) ) + if (size >= sizeof(XMU565)) { static const XMVECTORF32 s_Scale = { 31.f, 63.f, 31.f, 1.f }; XMU565 * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(XMU565) + 1 ); icount += sizeof(XMU565) ) + for (size_t icount = 0; icount < (size - sizeof(XMU565) + 1); icount += sizeof(XMU565)) { - if ( sPtr >= ePtr ) break; - XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>( *sPtr++ ); - v = XMVectorMultiply( v, s_Scale ); - XMStoreU565( dPtr++, v ); + if (sPtr >= ePtr) break; + XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(*sPtr++); + v = XMVectorMultiply(v, s_Scale); + XMStoreU565(dPtr++, v); } return true; } return false; case DXGI_FORMAT_B5G5R5A1_UNORM: - if ( size >= sizeof(XMU555) ) + if (size >= sizeof(XMU555)) { static const XMVECTORF32 s_Scale = { 31.f, 31.f, 31.f, 1.f }; XMU555 * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(XMU555) + 1 ); icount += sizeof(XMU555) ) + for (size_t icount = 0; icount < (size - sizeof(XMU555) + 1); icount += sizeof(XMU555)) { - if ( sPtr >= ePtr ) break; - XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>( *sPtr++ ); - v = XMVectorMultiply( v, s_Scale ); - XMStoreU555( dPtr, v ); - dPtr->w = ( XMVectorGetW( v ) > threshold ) ? 1 : 0; + if (sPtr >= ePtr) break; + XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(*sPtr++); + v = XMVectorMultiply(v, s_Scale); + XMStoreU555(dPtr, v); + dPtr->w = (XMVectorGetW(v) > threshold) ? 1 : 0; ++dPtr; } return true; @@ -2064,15 +2087,15 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, case DXGI_FORMAT_B8G8R8A8_UNORM: case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: - if ( size >= sizeof(XMUBYTEN4) ) + if (size >= sizeof(XMUBYTEN4)) { XMUBYTEN4 * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(XMUBYTEN4) + 1 ); icount += sizeof(XMUBYTEN4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4)) { - if ( sPtr >= ePtr ) break; - XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>( *sPtr++ ); - v = XMVectorAdd( v, g_8BitBias ); - XMStoreUByteN4( dPtr++, v ); + if (sPtr >= ePtr) break; + XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(*sPtr++); + v = XMVectorAdd(v, g_8BitBias); + XMStoreUByteN4(dPtr++, v); } return true; } @@ -2080,30 +2103,30 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, case DXGI_FORMAT_B8G8R8X8_UNORM: case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: - if ( size >= sizeof(XMUBYTEN4) ) + if (size >= sizeof(XMUBYTEN4)) { XMUBYTEN4 * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(XMUBYTEN4) + 1 ); icount += sizeof(XMUBYTEN4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4)) { - if ( sPtr >= ePtr ) break; - XMVECTOR v = XMVectorPermute<2, 1, 0, 7>( *sPtr++, g_XMIdentityR3 ); - v = XMVectorAdd( v, g_8BitBias ); - XMStoreUByteN4( dPtr++, v ); + if (sPtr >= ePtr) break; + XMVECTOR v = XMVectorPermute<2, 1, 0, 7>(*sPtr++, g_XMIdentityR3); + v = XMVectorAdd(v, g_8BitBias); + XMStoreUByteN4(dPtr++, v); } return true; } return false; case DXGI_FORMAT_AYUV: - if ( size >= sizeof(XMUBYTEN4) ) + if (size >= sizeof(XMUBYTEN4)) { XMUBYTEN4 * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(XMUBYTEN4) + 1 ); icount += sizeof(XMUBYTEN4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4)) { - if ( sPtr >= ePtr ) break; - + if (sPtr >= ePtr) break; + XMUBYTEN4 rgba; - XMStoreUByteN4( &rgba, *sPtr++ ); + XMStoreUByteN4(&rgba, *sPtr++); // http://msdn.microsoft.com/en-us/library/windows/desktop/dd206750.aspx @@ -2111,13 +2134,13 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, // 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; + 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->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; } @@ -2126,15 +2149,15 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, return false; case DXGI_FORMAT_Y410: - if ( size >= sizeof(XMUDECN4) ) + if (size >= sizeof(XMUDECN4)) { XMUDECN4 * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(XMUDECN4) + 1 ); icount += sizeof(XMUDECN4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUDECN4) + 1); icount += sizeof(XMUDECN4)) { - if ( sPtr >= ePtr ) break; - + if (sPtr >= ePtr) break; + XMUDECN4 rgba; - XMStoreUDecN4( &rgba, *sPtr++ ); + XMStoreUDecN4(&rgba, *sPtr++); // http://msdn.microsoft.com/en-us/library/windows/desktop/bb970578.aspx @@ -2146,13 +2169,13 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, 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; + 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->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; } @@ -2161,15 +2184,15 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, return false; case DXGI_FORMAT_Y416: - if ( size >= sizeof(XMUSHORTN4) ) + if (size >= sizeof(XMUSHORTN4)) { XMUSHORTN4 * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(XMUSHORTN4) + 1 ); icount += sizeof(XMUSHORTN4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUSHORTN4) + 1); icount += sizeof(XMUSHORTN4)) { - if ( sPtr >= ePtr ) break; - + if (sPtr >= ePtr) break; + XMUSHORTN4 rgba; - XMStoreUShortN4( &rgba, *sPtr++ ); + XMStoreUShortN4(&rgba, *sPtr++); // http://msdn.microsoft.com/en-us/library/windows/desktop/bb970578.aspx @@ -2181,13 +2204,13 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, 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; + 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->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; } @@ -2196,39 +2219,39 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, return false; case DXGI_FORMAT_YUY2: - if ( size >= sizeof(XMUBYTEN4) ) + if (size >= sizeof(XMUBYTEN4)) { XMUBYTEN4 * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(XMUBYTEN4) + 1 ); icount += sizeof(XMUBYTEN4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4)) { - if ( sPtr >= ePtr ) break; - + if (sPtr >= ePtr) break; + XMUBYTEN4 rgb1; - XMStoreUByteN4( &rgb1, *sPtr++ ); + 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; + 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) + if (sPtr < ePtr) { - XMStoreUByteN4( &rgb2, *sPtr++ ); + 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; + 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->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; @@ -2237,29 +2260,29 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, case DXGI_FORMAT_Y210: // Same as Y216 with least significant 6 bits set to zero - if ( size >= sizeof(XMUSHORTN4) ) + if (size >= sizeof(XMUSHORTN4)) { XMUSHORTN4 * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(XMUSHORTN4) + 1 ); icount += sizeof(XMUSHORTN4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUSHORTN4) + 1); icount += sizeof(XMUSHORTN4)) { - if ( sPtr >= ePtr ) break; + if (sPtr >= ePtr) break; XMUDECN4 rgb1; - XMStoreUDecN4( &rgb1, *sPtr++ ); + 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; + 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) + if (sPtr < ePtr) { - XMStoreUDecN4( &rgb2, *sPtr++ ); + XMStoreUDecN4(&rgb2, *sPtr++); } else { @@ -2270,14 +2293,14 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, 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; + 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->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; @@ -2285,29 +2308,29 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, return false; case DXGI_FORMAT_Y216: - if ( size >= sizeof(XMUSHORTN4) ) + if (size >= sizeof(XMUSHORTN4)) { XMUSHORTN4 * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(XMUSHORTN4) + 1 ); icount += sizeof(XMUSHORTN4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUSHORTN4) + 1); icount += sizeof(XMUSHORTN4)) { - if ( sPtr >= ePtr ) break; + if (sPtr >= ePtr) break; XMUSHORTN4 rgb1; - XMStoreUShortN4( &rgb1, *sPtr++ ); + 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; + 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) + if (sPtr < ePtr) { - XMStoreUShortN4( &rgb2, *sPtr++ ); + XMStoreUShortN4(&rgb2, *sPtr++); } else { @@ -2318,14 +2341,14 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, 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; + 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->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; @@ -2333,16 +2356,16 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, return false; case DXGI_FORMAT_B4G4R4A4_UNORM: - if ( size >= sizeof(XMUNIBBLE4) ) + if (size >= sizeof(XMUNIBBLE4)) { static const XMVECTORF32 s_Scale = { 15.f, 15.f, 15.f, 15.f }; XMUNIBBLE4 * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(XMUNIBBLE4) + 1 ); icount += sizeof(XMUNIBBLE4) ) + for (size_t icount = 0; icount < (size - sizeof(XMUNIBBLE4) + 1); icount += sizeof(XMUNIBBLE4)) { - if ( sPtr >= ePtr ) break; - XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>( *sPtr++ ); - v = XMVectorMultiply( v, s_Scale ); - XMStoreUNibble4( dPtr++, v ); + if (sPtr >= ePtr) break; + XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(*sPtr++); + v = XMVectorMultiply(v, s_Scale); + XMStoreUNibble4(dPtr++, v); } return true; } @@ -2350,25 +2373,25 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, case XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT: // Xbox One specific 7e3 format with alpha - if ( size >= sizeof(XMUDECN4) ) + 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 }; + 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) ) + for (size_t icount = 0; icount < (size - sizeof(XMUDECN4) + 1); icount += sizeof(XMUDECN4)) { - if ( sPtr >= ePtr ) break; + if (sPtr >= ePtr) break; - XMVECTOR V = XMVectorMultiply( *sPtr++, Scale ); - V = XMVectorClamp( V, g_XMZero, C ); + XMVECTOR V = XMVectorMultiply(*sPtr++, Scale); + V = XMVectorClamp(V, g_XMZero, C); XMFLOAT4A tmp; - XMStoreFloat4A( &tmp, V ); + XMStoreFloat4A(&tmp, V); - dPtr->x = FloatTo7e3( tmp.x ); - dPtr->y = FloatTo7e3( tmp.y ); - dPtr->z = FloatTo7e3( tmp.z ); + dPtr->x = FloatTo7e3(tmp.x); + dPtr->y = FloatTo7e3(tmp.y); + dPtr->z = FloatTo7e3(tmp.z); dPtr->w = (uint32_t)tmp.w; ++dPtr; } @@ -2378,25 +2401,25 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, case XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT: // Xbox One specific 6e4 format with alpha - if ( size >= sizeof(XMUDECN4) ) + 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 }; + 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) ) + for (size_t icount = 0; icount < (size - sizeof(XMUDECN4) + 1); icount += sizeof(XMUDECN4)) { - if ( sPtr >= ePtr ) break; + if (sPtr >= ePtr) break; - XMVECTOR V = XMVectorMultiply( *sPtr++, Scale ); - V = XMVectorClamp( V, g_XMZero, C ); + XMVECTOR V = XMVectorMultiply(*sPtr++, Scale); + V = XMVectorClamp(V, g_XMZero, C); XMFLOAT4A tmp; - XMStoreFloat4A( &tmp, V ); + XMStoreFloat4A(&tmp, V); - dPtr->x = FloatTo6e4( tmp.x ); - dPtr->y = FloatTo6e4( tmp.y ); - dPtr->z = FloatTo6e4( tmp.z ); + dPtr->x = FloatTo6e4(tmp.x); + dPtr->y = FloatTo6e4(tmp.y); + dPtr->z = FloatTo6e4(tmp.z); dPtr->w = (uint32_t)tmp.w; ++dPtr; } @@ -2406,29 +2429,29 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM: // Xbox One specific format - STORE_SCANLINE( XMXDECN4, XMStoreXDecN4 ); + STORE_SCANLINE(XMXDECN4, XMStoreXDecN4); case XBOX_DXGI_FORMAT_R4G4_UNORM: // Xbox One specific format - if ( size >= sizeof(uint8_t) ) + if (size >= sizeof(uint8_t)) { static const XMVECTORF32 s_Scale = { 15.f, 15.f, 0.f, 0.f }; uint8_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t icount = 0; icount < ( size - sizeof(uint8_t) + 1 ); icount += sizeof(uint8_t) ) + for (size_t icount = 0; icount < (size - sizeof(uint8_t) + 1); icount += sizeof(uint8_t)) { - if ( sPtr >= ePtr ) break; - XMVECTOR v = XMVectorMultiply( *sPtr++, s_Scale ); + if (sPtr >= ePtr) break; + XMVECTOR v = XMVectorMultiply(*sPtr++, s_Scale); XMUNIBBLE4 nibble; - XMStoreUNibble4( &nibble, v ); - *dPtr = static_cast( nibble.v ); + XMStoreUNibble4(&nibble, v); + *dPtr = static_cast(nibble.v); ++dPtr; } return true; } return false; - // We don't support the planar or palettized formats + // We don't support the planar or palettized formats default: return false; @@ -2442,33 +2465,33 @@ bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format, // Convert DXGI image to/from GUID_WICPixelFormat128bppRGBAFloat (no range conversions) //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT _ConvertToR32G32B32A32( const Image& srcImage, ScratchImage& image ) +HRESULT DirectX::_ConvertToR32G32B32A32(const Image& srcImage, ScratchImage& image) { - if ( !srcImage.pixels ) + if (!srcImage.pixels) return E_POINTER; - HRESULT hr = image.Initialize2D( DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.width, srcImage.height, 1, 1 ); - if ( FAILED(hr) ) + HRESULT hr = image.Initialize2D(DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.width, srcImage.height, 1, 1); + if (FAILED(hr)) return hr; - const Image *img = image.GetImage( 0, 0, 0 ); - if ( !img ) + const Image *img = image.GetImage(0, 0, 0); + if (!img) { image.Release(); return E_POINTER; } uint8_t* pDest = img->pixels; - if ( !pDest ) + if (!pDest) { image.Release(); return E_POINTER; } const uint8_t *pSrc = srcImage.pixels; - for( size_t h = 0; h < srcImage.height; ++h ) + for (size_t h = 0; h < srcImage.height; ++h) { - if ( !_LoadScanline( reinterpret_cast(pDest), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) ) + if (!_LoadScanline(reinterpret_cast(pDest), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format)) { image.Release(); return E_FAIL; @@ -2482,22 +2505,22 @@ HRESULT _ConvertToR32G32B32A32( const Image& srcImage, ScratchImage& image ) } _Use_decl_annotations_ -HRESULT _ConvertFromR32G32B32A32( const Image& srcImage, const Image& destImage ) +HRESULT DirectX::_ConvertFromR32G32B32A32(const Image& srcImage, const Image& destImage) { - assert( srcImage.format == DXGI_FORMAT_R32G32B32A32_FLOAT ); + assert(srcImage.format == DXGI_FORMAT_R32G32B32A32_FLOAT); - if ( !srcImage.pixels || !destImage.pixels ) + if (!srcImage.pixels || !destImage.pixels) return E_POINTER; - if ( srcImage.width != destImage.width || srcImage.height != destImage.height ) + if (srcImage.width != destImage.width || srcImage.height != destImage.height) return E_FAIL; const uint8_t *pSrc = srcImage.pixels; uint8_t* pDest = destImage.pixels; - for( size_t h = 0; h < srcImage.height; ++h ) + for (size_t h = 0; h < srcImage.height; ++h) { - if ( !_StoreScanline( pDest, destImage.rowPitch, destImage.format, reinterpret_cast(pSrc), srcImage.width ) ) + if (!_StoreScanline(pDest, destImage.rowPitch, destImage.format, reinterpret_cast(pSrc), srcImage.width)) return E_FAIL; pSrc += srcImage.rowPitch; @@ -2508,24 +2531,24 @@ HRESULT _ConvertFromR32G32B32A32( const Image& srcImage, const Image& destImage } _Use_decl_annotations_ -HRESULT _ConvertFromR32G32B32A32( const Image& srcImage, DXGI_FORMAT format, ScratchImage& image ) +HRESULT DirectX::_ConvertFromR32G32B32A32(const Image& srcImage, DXGI_FORMAT format, ScratchImage& image) { - if ( !srcImage.pixels ) + if (!srcImage.pixels) return E_POINTER; - HRESULT hr = image.Initialize2D( format, srcImage.width, srcImage.height, 1, 1 ); - if ( FAILED(hr) ) + HRESULT hr = image.Initialize2D(format, srcImage.width, srcImage.height, 1, 1); + if (FAILED(hr)) return hr; - const Image *img = image.GetImage( 0, 0, 0 ); - if ( !img ) + const Image *img = image.GetImage(0, 0, 0); + if (!img) { image.Release(); return E_POINTER; } - hr = _ConvertFromR32G32B32A32( srcImage, *img ); - if ( FAILED(hr) ) + hr = _ConvertFromR32G32B32A32(srcImage, *img); + if (FAILED(hr)) { image.Release(); return hr; @@ -2535,43 +2558,48 @@ HRESULT _ConvertFromR32G32B32A32( const Image& srcImage, DXGI_FORMAT format, Scr } _Use_decl_annotations_ -HRESULT _ConvertFromR32G32B32A32( const Image* srcImages, size_t nimages, const TexMetadata& metadata, DXGI_FORMAT format, ScratchImage& result ) +HRESULT DirectX::_ConvertFromR32G32B32A32( + const Image* srcImages, + size_t nimages, + const TexMetadata& metadata, + DXGI_FORMAT format, + ScratchImage& result) { - if ( !srcImages ) + if (!srcImages) return E_POINTER; result.Release(); - assert( metadata.format == DXGI_FORMAT_R32G32B32A32_FLOAT ); + assert(metadata.format == DXGI_FORMAT_R32G32B32A32_FLOAT); TexMetadata mdata2 = metadata; mdata2.format = format; - HRESULT hr = result.Initialize( mdata2 ); - if ( FAILED(hr) ) + HRESULT hr = result.Initialize(mdata2); + if (FAILED(hr)) return hr; - if ( nimages != result.GetImageCount() ) + if (nimages != result.GetImageCount()) { result.Release(); return E_FAIL; } const Image* dest = result.GetImages(); - if ( !dest ) + if (!dest) { result.Release(); return E_POINTER; } - for( size_t index=0; index < nimages; ++index ) + for (size_t index = 0; index < nimages; ++index) { - const Image& src = srcImages[ index ]; - const Image& dst = dest[ index ]; + const Image& src = srcImages[index]; + const Image& dst = dest[index]; - assert( src.format == DXGI_FORMAT_R32G32B32A32_FLOAT ); - assert( dst.format == format ); + assert(src.format == DXGI_FORMAT_R32G32B32A32_FLOAT); + assert(dst.format == format); - if ( src.width != dst.width || src.height != dst.height ) + if (src.width != dst.width || src.height != dst.height) { result.Release(); return E_FAIL; @@ -2579,15 +2607,15 @@ HRESULT _ConvertFromR32G32B32A32( const Image* srcImages, size_t nimages, const const uint8_t* pSrc = src.pixels; uint8_t* pDest = dst.pixels; - if ( !pSrc || !pDest ) + if (!pSrc || !pDest) { result.Release(); return E_POINTER; } - for( size_t h=0; h < src.height; ++h ) + for (size_t h = 0; h < src.height; ++h) { - if ( !_StoreScanline( pDest, dst.rowPitch, format, reinterpret_cast(pSrc), src.width ) ) + if (!_StoreScanline(pDest, dst.rowPitch, format, reinterpret_cast(pSrc), src.width)) { result.Release(); return E_FAIL; @@ -2610,14 +2638,20 @@ HRESULT _ConvertFromR32G32B32A32( const Image* srcImages, size_t nimages, const // where a = 0.055 //------------------------------------------------------------------------------------- _Use_decl_annotations_ -bool _StoreScanlineLinear( LPVOID pDestination, size_t size, DXGI_FORMAT format, - XMVECTOR* pSource, size_t count, DWORD flags, float threshold ) +bool DirectX::_StoreScanlineLinear( + void* pDestination, + size_t size, + DXGI_FORMAT format, + XMVECTOR* pSource, + size_t count, + DWORD flags, + float threshold) { - assert( pDestination && size > 0 ); - assert( pSource && count > 0 && (((uintptr_t)pSource & 0xF) == 0) ); - assert( IsValid(format) && !IsTypeless(format) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format) ); + assert(pDestination && size > 0); + assert(pSource && count > 0 && (((uintptr_t)pSource & 0xF) == 0)); + assert(IsValid(format) && !IsTypeless(format) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format)); - switch ( format ) + switch (format) { case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: @@ -2657,18 +2691,18 @@ bool _StoreScanlineLinear( LPVOID pDestination, size_t size, DXGI_FORMAT format, } // sRGB output processing (Linear RGB -> sRGB) - if ( flags & TEX_FILTER_SRGB_OUT ) + if (flags & TEX_FILTER_SRGB_OUT) { // To avoid the need for another temporary scanline buffer, we allow this function to overwrite the source buffer in-place // Given the intended usage in the filtering routines, this is not a problem. XMVECTOR* ptr = pSource; - for( size_t i=0; i < count; ++i, ++ptr ) + for (size_t i = 0; i < count; ++i, ++ptr) { - *ptr = XMColorRGBToSRGB( *ptr ); + *ptr = XMColorRGBToSRGB(*ptr); } } - return _StoreScanline( pDestination, size, format, pSource, count, threshold ); + return _StoreScanline(pDestination, size, format, pSource, count, threshold); } @@ -2680,14 +2714,19 @@ bool _StoreScanlineLinear( LPVOID pDestination, size_t size, DXGI_FORMAT format, // where a = 0.055 //------------------------------------------------------------------------------------- _Use_decl_annotations_ -bool _LoadScanlineLinear( XMVECTOR* pDestination, size_t count, - LPCVOID pSource, size_t size, DXGI_FORMAT format, DWORD flags ) +bool DirectX::_LoadScanlineLinear( + XMVECTOR* pDestination, + size_t count, + const void* pSource, + size_t size, + DXGI_FORMAT format, + DWORD flags) { - assert( pDestination && count > 0 && (((uintptr_t)pDestination & 0xF) == 0) ); - assert( pSource && size > 0 ); - assert( IsValid(format) && !IsTypeless(format,false) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format) ); + assert(pDestination && count > 0 && (((uintptr_t)pDestination & 0xF) == 0)); + assert(pSource && size > 0); + assert(IsValid(format) && !IsTypeless(format, false) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format)); - switch ( format ) + switch (format) { case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: @@ -2726,15 +2765,15 @@ bool _LoadScanlineLinear( XMVECTOR* pDestination, size_t count, break; } - if ( _LoadScanline( pDestination, count, pSource, size, format ) ) + if (_LoadScanline(pDestination, count, pSource, size, format)) { // sRGB input processing (sRGB -> Linear RGB) - if ( flags & TEX_FILTER_SRGB_IN ) + if (flags & TEX_FILTER_SRGB_IN) { XMVECTOR* ptr = pDestination; - for( size_t i=0; i < count; ++i, ++ptr ) + for (size_t i = 0; i < count; ++i, ++ptr) { - *ptr = XMColorSRGBToRGB( *ptr ); + *ptr = XMColorSRGBToRGB(*ptr); } } @@ -2748,169 +2787,173 @@ bool _LoadScanlineLinear( XMVECTOR* pDestination, size_t count, //------------------------------------------------------------------------------------- // Convert scanline based on source/target formats //------------------------------------------------------------------------------------- -struct ConvertData +namespace { - DXGI_FORMAT format; - size_t datasize; - DWORD flags; -}; + struct ConvertData + { + DXGI_FORMAT format; + size_t datasize; + DWORD flags; + }; -static const ConvertData g_ConvertTable[] = { - { DXGI_FORMAT_R32G32B32A32_FLOAT, 32, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_R32G32B32A32_UINT, 32, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_R32G32B32A32_SINT, 32, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_R32G32B32_FLOAT, 32, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B }, - { DXGI_FORMAT_R32G32B32_UINT, 32, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B }, - { DXGI_FORMAT_R32G32B32_SINT, 32, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B }, - { DXGI_FORMAT_R16G16B16A16_FLOAT, 16, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_R16G16B16A16_UNORM, 16, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_R16G16B16A16_UINT, 16, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_R16G16B16A16_SNORM, 16, CONVF_SNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_R16G16B16A16_SINT, 16, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_R32G32_FLOAT, 32, CONVF_FLOAT | CONVF_R | CONVF_G }, - { DXGI_FORMAT_R32G32_UINT, 32, CONVF_UINT | CONVF_R | CONVF_G }, - { DXGI_FORMAT_R32G32_SINT, 32, CONVF_SINT | CONVF_R | CONVF_G }, - { DXGI_FORMAT_D32_FLOAT_S8X24_UINT, 32, CONVF_FLOAT | CONVF_DEPTH | CONVF_STENCIL }, - { DXGI_FORMAT_R10G10B10A2_UNORM, 10, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_R10G10B10A2_UINT, 10, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_R11G11B10_FLOAT, 10, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B }, - { DXGI_FORMAT_R8G8B8A8_UNORM, 8, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 8, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_R8G8B8A8_UINT, 8, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_R8G8B8A8_SNORM, 8, CONVF_SNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_R8G8B8A8_SINT, 8, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_R16G16_FLOAT, 16, CONVF_FLOAT | CONVF_R | CONVF_G }, - { DXGI_FORMAT_R16G16_UNORM, 16, CONVF_UNORM | CONVF_R | CONVF_G }, - { DXGI_FORMAT_R16G16_UINT, 16, CONVF_UINT | CONVF_R | CONVF_G }, - { DXGI_FORMAT_R16G16_SNORM, 16, CONVF_SNORM | CONVF_R | CONVF_G }, - { DXGI_FORMAT_R16G16_SINT, 16, CONVF_SINT | CONVF_R | CONVF_G }, - { DXGI_FORMAT_D32_FLOAT, 32, CONVF_FLOAT | CONVF_DEPTH }, - { DXGI_FORMAT_R32_FLOAT, 32, CONVF_FLOAT | CONVF_R }, - { DXGI_FORMAT_R32_UINT, 32, CONVF_UINT | CONVF_R }, - { DXGI_FORMAT_R32_SINT, 32, CONVF_SINT | CONVF_R }, - { DXGI_FORMAT_D24_UNORM_S8_UINT, 32, CONVF_UNORM | CONVF_DEPTH | CONVF_STENCIL }, - { DXGI_FORMAT_R8G8_UNORM, 8, CONVF_UNORM | CONVF_R | CONVF_G }, - { DXGI_FORMAT_R8G8_UINT, 8, CONVF_UINT | CONVF_R | CONVF_G }, - { DXGI_FORMAT_R8G8_SNORM, 8, CONVF_SNORM | CONVF_R | CONVF_G }, - { DXGI_FORMAT_R8G8_SINT, 8, CONVF_SINT | CONVF_R | CONVF_G }, - { DXGI_FORMAT_R16_FLOAT, 16, CONVF_FLOAT | CONVF_R }, - { DXGI_FORMAT_D16_UNORM, 16, CONVF_UNORM | CONVF_DEPTH }, - { DXGI_FORMAT_R16_UNORM, 16, CONVF_UNORM | CONVF_R }, - { DXGI_FORMAT_R16_UINT, 16, CONVF_UINT | CONVF_R }, - { DXGI_FORMAT_R16_SNORM, 16, CONVF_SNORM | CONVF_R }, - { DXGI_FORMAT_R16_SINT, 16, CONVF_SINT | CONVF_R }, - { DXGI_FORMAT_R8_UNORM, 8, CONVF_UNORM | CONVF_R }, - { DXGI_FORMAT_R8_UINT, 8, CONVF_UINT | CONVF_R }, - { DXGI_FORMAT_R8_SNORM, 8, CONVF_SNORM | CONVF_R }, - { DXGI_FORMAT_R8_SINT, 8, CONVF_SINT | CONVF_R }, - { DXGI_FORMAT_A8_UNORM, 8, CONVF_UNORM | CONVF_A }, - { DXGI_FORMAT_R1_UNORM, 1, CONVF_UNORM | CONVF_R }, - { DXGI_FORMAT_R9G9B9E5_SHAREDEXP, 9, CONVF_SHAREDEXP | CONVF_R | CONVF_G | CONVF_B }, - { DXGI_FORMAT_R8G8_B8G8_UNORM, 8, CONVF_UNORM | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B }, - { DXGI_FORMAT_G8R8_G8B8_UNORM, 8, CONVF_UNORM | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B }, - { DXGI_FORMAT_BC1_UNORM, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_BC1_UNORM_SRGB, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_BC2_UNORM, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_BC2_UNORM_SRGB, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_BC3_UNORM, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_BC3_UNORM_SRGB, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_BC4_UNORM, 8, CONVF_UNORM | CONVF_BC | CONVF_R }, - { DXGI_FORMAT_BC4_SNORM, 8, CONVF_SNORM | CONVF_BC | CONVF_R }, - { DXGI_FORMAT_BC5_UNORM, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G }, - { DXGI_FORMAT_BC5_SNORM, 8, CONVF_SNORM | CONVF_BC | CONVF_R | CONVF_G }, - { DXGI_FORMAT_B5G6R5_UNORM, 5, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B }, - { DXGI_FORMAT_B5G5R5A1_UNORM, 5, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_B8G8R8A8_UNORM, 8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_B8G8R8X8_UNORM, 8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B }, - { DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM, 10, CONVF_UNORM | CONVF_XR | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, 8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, 8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B }, - { DXGI_FORMAT_BC6H_UF16, 16, CONVF_FLOAT | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { 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 }, - { XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT, 10, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT, 10, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM,10, CONVF_SNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, - { XBOX_DXGI_FORMAT_R4G4_UNORM, 4, CONVF_UNORM | CONVF_R | CONVF_G }, -}; + const ConvertData g_ConvertTable[] = + { + { DXGI_FORMAT_R32G32B32A32_FLOAT, 32, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_R32G32B32A32_UINT, 32, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_R32G32B32A32_SINT, 32, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_R32G32B32_FLOAT, 32, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B }, + { DXGI_FORMAT_R32G32B32_UINT, 32, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B }, + { DXGI_FORMAT_R32G32B32_SINT, 32, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B }, + { DXGI_FORMAT_R16G16B16A16_FLOAT, 16, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_R16G16B16A16_UNORM, 16, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_R16G16B16A16_UINT, 16, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_R16G16B16A16_SNORM, 16, CONVF_SNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_R16G16B16A16_SINT, 16, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_R32G32_FLOAT, 32, CONVF_FLOAT | CONVF_R | CONVF_G }, + { DXGI_FORMAT_R32G32_UINT, 32, CONVF_UINT | CONVF_R | CONVF_G }, + { DXGI_FORMAT_R32G32_SINT, 32, CONVF_SINT | CONVF_R | CONVF_G }, + { DXGI_FORMAT_D32_FLOAT_S8X24_UINT, 32, CONVF_FLOAT | CONVF_DEPTH | CONVF_STENCIL }, + { DXGI_FORMAT_R10G10B10A2_UNORM, 10, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_R10G10B10A2_UINT, 10, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_R11G11B10_FLOAT, 10, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B }, + { DXGI_FORMAT_R8G8B8A8_UNORM, 8, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 8, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_R8G8B8A8_UINT, 8, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_R8G8B8A8_SNORM, 8, CONVF_SNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_R8G8B8A8_SINT, 8, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_R16G16_FLOAT, 16, CONVF_FLOAT | CONVF_R | CONVF_G }, + { DXGI_FORMAT_R16G16_UNORM, 16, CONVF_UNORM | CONVF_R | CONVF_G }, + { DXGI_FORMAT_R16G16_UINT, 16, CONVF_UINT | CONVF_R | CONVF_G }, + { DXGI_FORMAT_R16G16_SNORM, 16, CONVF_SNORM | CONVF_R | CONVF_G }, + { DXGI_FORMAT_R16G16_SINT, 16, CONVF_SINT | CONVF_R | CONVF_G }, + { DXGI_FORMAT_D32_FLOAT, 32, CONVF_FLOAT | CONVF_DEPTH }, + { DXGI_FORMAT_R32_FLOAT, 32, CONVF_FLOAT | CONVF_R }, + { DXGI_FORMAT_R32_UINT, 32, CONVF_UINT | CONVF_R }, + { DXGI_FORMAT_R32_SINT, 32, CONVF_SINT | CONVF_R }, + { DXGI_FORMAT_D24_UNORM_S8_UINT, 32, CONVF_UNORM | CONVF_DEPTH | CONVF_STENCIL }, + { DXGI_FORMAT_R8G8_UNORM, 8, CONVF_UNORM | CONVF_R | CONVF_G }, + { DXGI_FORMAT_R8G8_UINT, 8, CONVF_UINT | CONVF_R | CONVF_G }, + { DXGI_FORMAT_R8G8_SNORM, 8, CONVF_SNORM | CONVF_R | CONVF_G }, + { DXGI_FORMAT_R8G8_SINT, 8, CONVF_SINT | CONVF_R | CONVF_G }, + { DXGI_FORMAT_R16_FLOAT, 16, CONVF_FLOAT | CONVF_R }, + { DXGI_FORMAT_D16_UNORM, 16, CONVF_UNORM | CONVF_DEPTH }, + { DXGI_FORMAT_R16_UNORM, 16, CONVF_UNORM | CONVF_R }, + { DXGI_FORMAT_R16_UINT, 16, CONVF_UINT | CONVF_R }, + { DXGI_FORMAT_R16_SNORM, 16, CONVF_SNORM | CONVF_R }, + { DXGI_FORMAT_R16_SINT, 16, CONVF_SINT | CONVF_R }, + { DXGI_FORMAT_R8_UNORM, 8, CONVF_UNORM | CONVF_R }, + { DXGI_FORMAT_R8_UINT, 8, CONVF_UINT | CONVF_R }, + { DXGI_FORMAT_R8_SNORM, 8, CONVF_SNORM | CONVF_R }, + { DXGI_FORMAT_R8_SINT, 8, CONVF_SINT | CONVF_R }, + { DXGI_FORMAT_A8_UNORM, 8, CONVF_UNORM | CONVF_A }, + { DXGI_FORMAT_R1_UNORM, 1, CONVF_UNORM | CONVF_R }, + { DXGI_FORMAT_R9G9B9E5_SHAREDEXP, 9, CONVF_SHAREDEXP | CONVF_R | CONVF_G | CONVF_B }, + { DXGI_FORMAT_R8G8_B8G8_UNORM, 8, CONVF_UNORM | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B }, + { DXGI_FORMAT_G8R8_G8B8_UNORM, 8, CONVF_UNORM | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B }, + { DXGI_FORMAT_BC1_UNORM, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_BC1_UNORM_SRGB, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_BC2_UNORM, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_BC2_UNORM_SRGB, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_BC3_UNORM, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_BC3_UNORM_SRGB, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_BC4_UNORM, 8, CONVF_UNORM | CONVF_BC | CONVF_R }, + { DXGI_FORMAT_BC4_SNORM, 8, CONVF_SNORM | CONVF_BC | CONVF_R }, + { DXGI_FORMAT_BC5_UNORM, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G }, + { DXGI_FORMAT_BC5_SNORM, 8, CONVF_SNORM | CONVF_BC | CONVF_R | CONVF_G }, + { DXGI_FORMAT_B5G6R5_UNORM, 5, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B }, + { DXGI_FORMAT_B5G5R5A1_UNORM, 5, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_B8G8R8A8_UNORM, 8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_B8G8R8X8_UNORM, 8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B }, + { DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM, 10, CONVF_UNORM | CONVF_XR | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, 8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, 8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B }, + { DXGI_FORMAT_BC6H_UF16, 16, CONVF_FLOAT | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { 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 }, + { XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT, 10, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT, 10, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM,10, CONVF_SNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, + { XBOX_DXGI_FORMAT_R4G4_UNORM, 4, CONVF_UNORM | CONVF_R | CONVF_G }, + }; #pragma prefast( suppress : 25004, "Signature must match bsearch_s" ); -static int __cdecl _ConvertCompare( void *context, const void* ptr1, const void *ptr2 ) -{ - UNREFERENCED_PARAMETER(context); - const ConvertData *p1 = reinterpret_cast(ptr1); - const ConvertData *p2 = reinterpret_cast(ptr2); - if ( p1->format == p2->format ) return 0; - else return (p1->format < p2->format ) ? -1 : 1; + int __cdecl _ConvertCompare(void *context, const void* ptr1, const void *ptr2) + { + UNREFERENCED_PARAMETER(context); + const ConvertData *p1 = reinterpret_cast(ptr1); + const ConvertData *p2 = reinterpret_cast(ptr2); + if (p1->format == p2->format) return 0; + else return (p1->format < p2->format) ? -1 : 1; + } } _Use_decl_annotations_ -DWORD _GetConvertFlags( DXGI_FORMAT format ) +DWORD DirectX::_GetConvertFlags(DXGI_FORMAT format) { #ifdef _DEBUG // Ensure conversion table is in ascending order - assert( _countof(g_ConvertTable) > 0 ); + assert(_countof(g_ConvertTable) > 0); DXGI_FORMAT lastvalue = g_ConvertTable[0].format; - for( size_t index=1; index < _countof(g_ConvertTable); ++index ) + for (size_t index = 1; index < _countof(g_ConvertTable); ++index) { - assert( g_ConvertTable[index].format > lastvalue ); + assert(g_ConvertTable[index].format > lastvalue); lastvalue = g_ConvertTable[index].format; } #endif ConvertData key = { format, 0 }; - const ConvertData* in = (const ConvertData*) bsearch_s( &key, g_ConvertTable, _countof(g_ConvertTable), sizeof(ConvertData), - _ConvertCompare, nullptr ); + const ConvertData* in = (const ConvertData*)bsearch_s(&key, g_ConvertTable, _countof(g_ConvertTable), sizeof(ConvertData), + _ConvertCompare, nullptr); return (in) ? in->flags : 0; } _Use_decl_annotations_ -void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, DXGI_FORMAT inFormat, DWORD flags ) +void DirectX::_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) && !IsTypeless(outFormat) && !IsPlanar(outFormat) && !IsPalettized(outFormat) ); - assert( IsValid(inFormat) && !IsTypeless(inFormat) && !IsPlanar(inFormat) && !IsPalettized(inFormat) ); + assert(pBuffer && count > 0 && (((uintptr_t)pBuffer & 0xF) == 0)); + assert(IsValid(outFormat) && !IsTypeless(outFormat) && !IsPlanar(outFormat) && !IsPalettized(outFormat)); + assert(IsValid(inFormat) && !IsTypeless(inFormat) && !IsPlanar(inFormat) && !IsPalettized(inFormat)); - if ( !pBuffer ) + if (!pBuffer) return; #ifdef _DEBUG // Ensure conversion table is in ascending order - assert( _countof(g_ConvertTable) > 0 ); + assert(_countof(g_ConvertTable) > 0); DXGI_FORMAT lastvalue = g_ConvertTable[0].format; - for( size_t index=1; index < _countof(g_ConvertTable); ++index ) + for (size_t index = 1; index < _countof(g_ConvertTable); ++index) { - assert( g_ConvertTable[index].format > lastvalue ); + assert(g_ConvertTable[index].format > lastvalue); lastvalue = g_ConvertTable[index].format; } #endif // Determine conversion details about source and dest formats ConvertData key = { inFormat, 0 }; - const ConvertData* in = (const ConvertData*) bsearch_s( &key, g_ConvertTable, _countof(g_ConvertTable), sizeof(ConvertData), - _ConvertCompare, nullptr ); + const ConvertData* in = (const ConvertData*)bsearch_s(&key, g_ConvertTable, _countof(g_ConvertTable), sizeof(ConvertData), + _ConvertCompare, nullptr); key.format = outFormat; - const ConvertData* out = (const ConvertData*) bsearch_s( &key, g_ConvertTable, _countof(g_ConvertTable), sizeof(ConvertData), - _ConvertCompare, nullptr ); - if ( !in || !out ) + const ConvertData* out = (const ConvertData*)bsearch_s(&key, g_ConvertTable, _countof(g_ConvertTable), sizeof(ConvertData), + _ConvertCompare, nullptr); + if (!in || !out) { assert(false); return; } - assert( _GetConvertFlags( inFormat ) == in->flags ); - assert( _GetConvertFlags( outFormat ) == out->flags ); + assert(_GetConvertFlags(inFormat) == in->flags); + assert(_GetConvertFlags(outFormat) == out->flags); // Handle SRGB filtering modes - switch ( inFormat ) + switch (inFormat) { case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: case DXGI_FORMAT_BC1_UNORM_SRGB: @@ -2928,7 +2971,7 @@ void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, D break; } - switch ( outFormat ) + switch (outFormat) { case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: case DXGI_FORMAT_BC1_UNORM_SRGB: @@ -2946,108 +2989,108 @@ void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, D break; } - if ( (flags & (TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT)) == (TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT) ) + if ((flags & (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT)) == (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT)) { - flags &= ~(TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT); + flags &= ~(TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT); } // sRGB input processing (sRGB -> Linear RGB) - if ( flags & TEX_FILTER_SRGB_IN ) + if (flags & TEX_FILTER_SRGB_IN) { - if ( !(in->flags & CONVF_DEPTH) && ( (in->flags & CONVF_FLOAT) || (in->flags & CONVF_UNORM) ) ) + if (!(in->flags & CONVF_DEPTH) && ((in->flags & CONVF_FLOAT) || (in->flags & CONVF_UNORM))) { XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i, ++ptr ) + for (size_t i = 0; i < count; ++i, ++ptr) { - *ptr = XMColorSRGBToRGB( *ptr ); + *ptr = XMColorSRGBToRGB(*ptr); } } } // Handle conversion special cases DWORD diffFlags = in->flags ^ out->flags; - if ( diffFlags != 0 ) + if (diffFlags != 0) { static const XMVECTORF32 s_two = { 2.0f, 2.0f, 2.0f, 2.0f }; - if ( diffFlags & CONVF_DEPTH ) + if (diffFlags & CONVF_DEPTH) { - if ( in->flags & CONVF_DEPTH ) + if (in->flags & CONVF_DEPTH) { // CONVF_DEPTH -> !CONVF_DEPTH - if ( in->flags & CONVF_STENCIL ) + if (in->flags & CONVF_STENCIL) { // Stencil -> Alpha static const XMVECTORF32 S = { 1.f, 1.f, 1.f, 255.f }; - if( out->flags & CONVF_UNORM ) + if (out->flags & CONVF_UNORM) { // UINT -> UNORM XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorSplatY( v ); - v1 = XMVectorClamp( v1, g_XMZero, S ); - v1 = XMVectorDivide( v1, S ); - v = XMVectorSelect( v1, v, g_XMSelect1110 ); + XMVECTOR v1 = XMVectorSplatY(v); + v1 = XMVectorClamp(v1, g_XMZero, S); + v1 = XMVectorDivide(v1, S); + v = XMVectorSelect(v1, v, g_XMSelect1110); *ptr++ = v; } } - else if ( out->flags & CONVF_SNORM ) + else if (out->flags & CONVF_SNORM) { // UINT -> SNORM XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorSplatY( v ); - v1 = XMVectorClamp( v1, g_XMZero, S ); - v1 = XMVectorDivide( v1, S ); - v1 = XMVectorMultiplyAdd( v1, s_two, g_XMNegativeOne ); - v = XMVectorSelect( v1, v, g_XMSelect1110 ); + XMVECTOR v1 = XMVectorSplatY(v); + v1 = XMVectorClamp(v1, g_XMZero, S); + v1 = XMVectorDivide(v1, S); + v1 = XMVectorMultiplyAdd(v1, s_two, g_XMNegativeOne); + v = XMVectorSelect(v1, v, g_XMSelect1110); *ptr++ = v; } } else { XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorSplatY( v ); - v = XMVectorSelect( v1, v, g_XMSelect1110 ); + XMVECTOR v1 = XMVectorSplatY(v); + v = XMVectorSelect(v1, v, g_XMSelect1110); *ptr++ = v; } } } // Depth -> RGB - if ( ( out->flags & CONVF_UNORM ) && ( in->flags & CONVF_FLOAT ) ) + if ((out->flags & CONVF_UNORM) && (in->flags & CONVF_FLOAT)) { // Depth FLOAT -> UNORM XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorSaturate( v ); - v1 = XMVectorSplatX( v1 ); - v = XMVectorSelect( v, v1, g_XMSelect1110 ); + XMVECTOR v1 = XMVectorSaturate(v); + v1 = XMVectorSplatX(v1); + v = XMVectorSelect(v, v1, g_XMSelect1110); *ptr++ = v; } } - else if ( out->flags & CONVF_SNORM ) + else if (out->flags & CONVF_SNORM) { - if ( in->flags & CONVF_UNORM ) + if (in->flags & CONVF_UNORM) { // Depth UNORM -> SNORM XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorMultiplyAdd( v, s_two, g_XMNegativeOne ); - v1 = XMVectorSplatX( v1 ); - v = XMVectorSelect( v, v1, g_XMSelect1110 ); + XMVECTOR v1 = XMVectorMultiplyAdd(v, s_two, g_XMNegativeOne); + v1 = XMVectorSplatX(v1); + v = XMVectorSelect(v, v1, g_XMSelect1110); *ptr++ = v; } } @@ -3055,12 +3098,12 @@ void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, D { // Depth FLOAT -> SNORM XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorClamp( v, g_XMNegativeOne, g_XMOne ); - v1 = XMVectorSplatX( v1 ); - v = XMVectorSelect( v, v1, g_XMSelect1110 ); + XMVECTOR v1 = XMVectorClamp(v, g_XMNegativeOne, g_XMOne); + v1 = XMVectorSplatX(v1); + v = XMVectorSelect(v, v1, g_XMSelect1110); *ptr++ = v; } } @@ -3068,11 +3111,11 @@ void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, D else { XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorSplatX( v ); - v = XMVectorSelect( v, v1, g_XMSelect1110 ); + XMVECTOR v1 = XMVectorSplatX(v); + v = XMVectorSelect(v, v1, g_XMSelect1110); *ptr++ = v; } } @@ -3082,43 +3125,43 @@ void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, D // !CONVF_DEPTH -> CONVF_DEPTH // RGB -> Depth (red channel) - switch( flags & ( TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN | TEX_FILTER_RGB_COPY_BLUE ) ) + switch (flags & (TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN | TEX_FILTER_RGB_COPY_BLUE)) { case TEX_FILTER_RGB_COPY_GREEN: + { + XMVECTOR* ptr = pBuffer; + for (size_t i = 0; i < count; ++i) { - XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) - { - XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorSplatY( v ); - v = XMVectorSelect( v, v1, g_XMSelect1000 ); - *ptr++ = v; - } + XMVECTOR v = *ptr; + XMVECTOR v1 = XMVectorSplatY(v); + v = XMVectorSelect(v, v1, g_XMSelect1000); + *ptr++ = v; } - break; + } + break; case TEX_FILTER_RGB_COPY_BLUE: + { + XMVECTOR* ptr = pBuffer; + for (size_t i = 0; i < count; ++i) { - XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) - { - XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorSplatZ( v ); - v = XMVectorSelect( v, v1, g_XMSelect1000 ); - *ptr++ = v; - } + XMVECTOR v = *ptr; + XMVECTOR v1 = XMVectorSplatZ(v); + v = XMVectorSelect(v, v1, g_XMSelect1000); + *ptr++ = v; } - break; + } + break; default: - if ( (in->flags & CONVF_UNORM) && ( (in->flags & CONVF_RGB_MASK) == (CONVF_R|CONVF_G|CONVF_B) ) ) + if ((in->flags & CONVF_UNORM) && ((in->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G | CONVF_B))) { XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - XMVECTOR v1 = XMVector3Dot( v, g_Grayscale ); - v = XMVectorSelect( v, v1, g_XMSelect1000 ); + XMVECTOR v1 = XMVector3Dot(v, g_Grayscale); + v = XMVectorSelect(v, v1, g_XMSelect1000); *ptr++ = v; } break; @@ -3127,157 +3170,157 @@ void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, D // fall-through case TEX_FILTER_RGB_COPY_RED: + { + XMVECTOR* ptr = pBuffer; + for (size_t i = 0; i < count; ++i) { - XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) - { - XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorSplatX( v ); - v = XMVectorSelect( v, v1, g_XMSelect1000 ); - *ptr++ = v; - } + XMVECTOR v = *ptr; + XMVECTOR v1 = XMVectorSplatX(v); + v = XMVectorSelect(v, v1, g_XMSelect1000); + *ptr++ = v; } - break; + } + break; } // Finialize type conversion for depth (red channel) - if ( out->flags & CONVF_UNORM ) + if (out->flags & CONVF_UNORM) { - if ( in->flags & CONVF_SNORM ) + if (in->flags & CONVF_SNORM) { // SNORM -> UNORM XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorMultiplyAdd( v, g_XMOneHalf, g_XMOneHalf ); - v = XMVectorSelect( v, v1, g_XMSelect1000 ); + XMVECTOR v1 = XMVectorMultiplyAdd(v, g_XMOneHalf, g_XMOneHalf); + v = XMVectorSelect(v, v1, g_XMSelect1000); *ptr++ = v; } } - else if ( in->flags & CONVF_FLOAT ) + else if (in->flags & CONVF_FLOAT) { // FLOAT -> UNORM XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorSaturate( v ); - v = XMVectorSelect( v, v1, g_XMSelect1000 ); + XMVECTOR v1 = XMVectorSaturate(v); + v = XMVectorSelect(v, v1, g_XMSelect1000); *ptr++ = v; } } } - if ( out->flags & CONVF_STENCIL ) + if (out->flags & CONVF_STENCIL) { // Alpha -> Stencil (green channel) static const XMVECTORU32 select0100 = { XM_SELECT_0, XM_SELECT_1, XM_SELECT_0, XM_SELECT_0 }; static const XMVECTORF32 S = { 255.f, 255.f, 255.f, 255.f }; - if ( in->flags & CONVF_UNORM ) + if (in->flags & CONVF_UNORM) { // UNORM -> UINT XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorMultiply( v, S ); - v1 = XMVectorSplatW( v1 ); - v = XMVectorSelect( v, v1, select0100 ); + XMVECTOR v1 = XMVectorMultiply(v, S); + v1 = XMVectorSplatW(v1); + v = XMVectorSelect(v, v1, select0100); *ptr++ = v; } } - else if ( in->flags & CONVF_SNORM ) + else if (in->flags & CONVF_SNORM) { // SNORM -> UINT XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorMultiplyAdd( v, g_XMOneHalf, g_XMOneHalf ); - v1 = XMVectorMultiply( v1, S ); - v1 = XMVectorSplatW( v1 ); - v = XMVectorSelect( v, v1, select0100 ); + XMVECTOR v1 = XMVectorMultiplyAdd(v, g_XMOneHalf, g_XMOneHalf); + v1 = XMVectorMultiply(v1, S); + v1 = XMVectorSplatW(v1); + v = XMVectorSelect(v, v1, select0100); *ptr++ = v; } } else { XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorSplatW( v ); - v = XMVectorSelect( v, v1, select0100 ); + XMVECTOR v1 = XMVectorSplatW(v); + v = XMVectorSelect(v, v1, select0100); *ptr++ = v; } } } } } - else if ( out->flags & CONVF_DEPTH ) + else if (out->flags & CONVF_DEPTH) { // CONVF_DEPTH -> CONVF_DEPTH - if ( diffFlags & CONVF_FLOAT ) + if (diffFlags & CONVF_FLOAT) { - if ( in->flags & CONVF_FLOAT ) + if (in->flags & CONVF_FLOAT) { // FLOAT -> UNORM depth, preserve stencil XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorSaturate( v ); - v = XMVectorSelect( v, v1, g_XMSelect1000 ); + XMVECTOR v1 = XMVectorSaturate(v); + v = XMVectorSelect(v, v1, g_XMSelect1000); *ptr++ = v; } } } } - else if ( out->flags & CONVF_UNORM ) + else if (out->flags & CONVF_UNORM) { - if ( in->flags & CONVF_SNORM ) + if (in->flags & CONVF_SNORM) { // SNORM -> UNORM XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - *ptr++ = XMVectorMultiplyAdd( v, g_XMOneHalf, g_XMOneHalf ); + *ptr++ = XMVectorMultiplyAdd(v, g_XMOneHalf, g_XMOneHalf); } } - else if ( in->flags & CONVF_FLOAT ) + else if (in->flags & CONVF_FLOAT) { // FLOAT -> UNORM XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - *ptr++ = XMVectorSaturate( v ); + *ptr++ = XMVectorSaturate(v); } } } - else if ( out->flags & CONVF_SNORM ) + else if (out->flags & CONVF_SNORM) { - if ( in->flags & CONVF_UNORM ) + if (in->flags & CONVF_UNORM) { // UNORM -> SNORM XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - *ptr++ = XMVectorMultiplyAdd( v, s_two, g_XMNegativeOne ); + *ptr++ = XMVectorMultiplyAdd(v, s_two, g_XMNegativeOne); } } - else if ( in->flags & CONVF_FLOAT ) + else if (in->flags & CONVF_FLOAT) { // FLOAT -> SNORM XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - *ptr++ = XMVectorClamp( v, g_XMNegativeOne, g_XMOne ); + *ptr++ = XMVectorClamp(v, g_XMNegativeOne, g_XMOne); } } } @@ -3286,41 +3329,41 @@ void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, D // CONVF_PACKED cases are handled because LoadScanline/StoreScanline handles packing/unpacking - if ( ((out->flags & CONVF_RGBA_MASK) == CONVF_A) && !(in->flags & CONVF_A) ) + if (((out->flags & CONVF_RGBA_MASK) == CONVF_A) && !(in->flags & CONVF_A)) { // !CONVF_A -> A format - switch( flags & ( TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN | TEX_FILTER_RGB_COPY_BLUE ) ) + switch (flags & (TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN | TEX_FILTER_RGB_COPY_BLUE)) { case TEX_FILTER_RGB_COPY_GREEN: + { + XMVECTOR* ptr = pBuffer; + for (size_t i = 0; i < count; ++i) { - XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) - { - XMVECTOR v = *ptr; - *ptr++ = XMVectorSplatY( v ); - } + XMVECTOR v = *ptr; + *ptr++ = XMVectorSplatY(v); } - break; + } + break; case TEX_FILTER_RGB_COPY_BLUE: + { + XMVECTOR* ptr = pBuffer; + for (size_t i = 0; i < count; ++i) { - XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) - { - XMVECTOR v = *ptr; - *ptr++ = XMVectorSplatZ( v ); - } + XMVECTOR v = *ptr; + *ptr++ = XMVectorSplatZ(v); } - break; + } + break; default: - if ( (in->flags & CONVF_UNORM) && ( (in->flags & CONVF_RGB_MASK) == (CONVF_R|CONVF_G|CONVF_B) ) ) + if ((in->flags & CONVF_UNORM) && ((in->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G | CONVF_B))) { XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - *ptr++ = XMVector3Dot( v, g_Grayscale ); + *ptr++ = XMVector3Dot(v, g_Grayscale); } break; } @@ -3328,92 +3371,92 @@ void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, D // fall-through case TEX_FILTER_RGB_COPY_RED: + { + XMVECTOR* ptr = pBuffer; + for (size_t i = 0; i < count; ++i) { - XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) - { - XMVECTOR v = *ptr; - *ptr++ = XMVectorSplatX( v ); - } + XMVECTOR v = *ptr; + *ptr++ = XMVectorSplatX(v); } - break; + } + break; } } - else if ( ((in->flags & CONVF_RGBA_MASK) == CONVF_A) && !(out->flags & CONVF_A) ) + else if (((in->flags & CONVF_RGBA_MASK) == CONVF_A) && !(out->flags & CONVF_A)) { // A format -> !CONVF_A XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - *ptr++ = XMVectorSplatW( v ); + *ptr++ = XMVectorSplatW(v); } } - else if ( (in->flags & CONVF_RGB_MASK) == CONVF_R ) + else if ((in->flags & CONVF_RGB_MASK) == CONVF_R) { - if ( (out->flags & CONVF_RGB_MASK) == (CONVF_R|CONVF_G|CONVF_B) ) + if ((out->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G | CONVF_B)) { // R format -> RGB format XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorSplatX( v ); - *ptr++ = XMVectorSelect( v, v1, g_XMSelect1110 ); + XMVECTOR v1 = XMVectorSplatX(v); + *ptr++ = XMVectorSelect(v, v1, g_XMSelect1110); } } - else if ( (out->flags & CONVF_RGB_MASK) == (CONVF_R|CONVF_G) ) + else if ((out->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G)) { // R format -> RG format XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorSplatX( v ); - *ptr++ = XMVectorSelect( v, v1, g_XMSelect1100 ); + XMVECTOR v1 = XMVectorSplatX(v); + *ptr++ = XMVectorSelect(v, v1, g_XMSelect1100); } } } - else if ( (in->flags & CONVF_RGB_MASK) == (CONVF_R|CONVF_G|CONVF_B) ) + else if ((in->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G | CONVF_B)) { - if ( (out->flags & CONVF_RGB_MASK) == CONVF_R ) + if ((out->flags & CONVF_RGB_MASK) == CONVF_R) { // RGB format -> R format - switch( flags & ( TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN | TEX_FILTER_RGB_COPY_BLUE ) ) + switch (flags & (TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN | TEX_FILTER_RGB_COPY_BLUE)) { case TEX_FILTER_RGB_COPY_GREEN: + { + XMVECTOR* ptr = pBuffer; + for (size_t i = 0; i < count; ++i) { - XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) - { - XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorSplatY( v ); - *ptr++ = XMVectorSelect( v, v1, g_XMSelect1110 ); - } + XMVECTOR v = *ptr; + XMVECTOR v1 = XMVectorSplatY(v); + *ptr++ = XMVectorSelect(v, v1, g_XMSelect1110); } - break; + } + break; case TEX_FILTER_RGB_COPY_BLUE: + { + XMVECTOR* ptr = pBuffer; + for (size_t i = 0; i < count; ++i) { - XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) - { - XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorSplatZ( v ); - *ptr++ = XMVectorSelect( v, v1, g_XMSelect1110 ); - } + XMVECTOR v = *ptr; + XMVECTOR v1 = XMVectorSplatZ(v); + *ptr++ = XMVectorSelect(v, v1, g_XMSelect1110); } - break; + } + break; default: - if ( in->flags & CONVF_UNORM ) + if (in->flags & CONVF_UNORM) { XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { XMVECTOR v = *ptr; - XMVECTOR v1 = XMVector3Dot( v, g_Grayscale ); - *ptr++ = XMVectorSelect( v, v1, g_XMSelect1110 ); + XMVECTOR v1 = XMVector3Dot(v, g_Grayscale); + *ptr++ = XMVectorSelect(v, v1, g_XMSelect1110); } break; } @@ -3425,34 +3468,34 @@ void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, D break; } } - else if ( (out->flags & CONVF_RGB_MASK) == (CONVF_R|CONVF_G) ) + else if ((out->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G)) { // RGB format -> RG format - switch( flags & ( TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN | TEX_FILTER_RGB_COPY_BLUE ) ) + switch (flags & (TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN | TEX_FILTER_RGB_COPY_BLUE)) { case TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_BLUE: + { + XMVECTOR* ptr = pBuffer; + for (size_t i = 0; i < count; ++i) { - XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) - { - XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorSwizzle<0,2,0,2>( v ); - *ptr++ = XMVectorSelect( v, v1, g_XMSelect1100 ); - } + XMVECTOR v = *ptr; + XMVECTOR v1 = XMVectorSwizzle<0, 2, 0, 2>(v); + *ptr++ = XMVectorSelect(v, v1, g_XMSelect1100); } - break; + } + break; case TEX_FILTER_RGB_COPY_GREEN | TEX_FILTER_RGB_COPY_BLUE: + { + XMVECTOR* ptr = pBuffer; + for (size_t i = 0; i < count; ++i) { - XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i ) - { - XMVECTOR v = *ptr; - XMVECTOR v1 = XMVectorSwizzle<1,2,3,0>( v ); - *ptr++ = XMVectorSelect( v, v1, g_XMSelect1100 ); - } + XMVECTOR v = *ptr; + XMVECTOR v1 = XMVectorSwizzle<1, 2, 3, 0>(v); + *ptr++ = XMVectorSelect(v, v1, g_XMSelect1100); } - break; + } + break; case TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN: default: @@ -3464,14 +3507,14 @@ void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, D } // sRGB output processing (Linear RGB -> sRGB) - if ( flags & TEX_FILTER_SRGB_OUT ) + if (flags & TEX_FILTER_SRGB_OUT) { - if ( !(out->flags & CONVF_DEPTH) && ( (out->flags & CONVF_FLOAT) || (out->flags & CONVF_UNORM) ) ) + if (!(out->flags & CONVF_DEPTH) && ((out->flags & CONVF_FLOAT) || (out->flags & CONVF_UNORM))) { XMVECTOR* ptr = pBuffer; - for( size_t i=0; i < count; ++i, ++ptr ) + for (size_t i = 0; i < count; ++i, ++ptr) { - *ptr = XMColorRGBToSRGB( *ptr ); + *ptr = XMColorRGBToSRGB(*ptr); } } } @@ -3481,31 +3524,32 @@ void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, D //------------------------------------------------------------------------------------- // Dithering //------------------------------------------------------------------------------------- - -// 4X4X4 ordered dithering matrix -static const float g_Dither[] = +namespace { - // (z & 3) + ( (y & 3) * 8) + (x & 3) - 0.468750f, -0.031250f, 0.343750f, -0.156250f, 0.468750f, -0.031250f, 0.343750f, -0.156250f, - -0.281250f, 0.218750f, -0.406250f, 0.093750f, -0.281250f, 0.218750f, -0.406250f, 0.093750f, - 0.281250f, -0.218750f, 0.406250f, -0.093750f, 0.281250f, -0.218750f, 0.406250f, -0.093750f, - -0.468750f, 0.031250f, -0.343750f, 0.156250f, -0.468750f, 0.031250f, -0.343750f, 0.156250f, -}; + // 4X4X4 ordered dithering matrix + const float g_Dither[] = + { + // (z & 3) + ( (y & 3) * 8) + (x & 3) + 0.468750f, -0.031250f, 0.343750f, -0.156250f, 0.468750f, -0.031250f, 0.343750f, -0.156250f, + -0.281250f, 0.218750f, -0.406250f, 0.093750f, -0.281250f, 0.218750f, -0.406250f, 0.093750f, + 0.281250f, -0.218750f, 0.406250f, -0.093750f, 0.281250f, -0.218750f, 0.406250f, -0.093750f, + -0.468750f, 0.031250f, -0.343750f, 0.156250f, -0.468750f, 0.031250f, -0.343750f, 0.156250f, + }; -static const XMVECTORF32 g_Scale16pc = { 65535.f, 65535.f, 65535.f, 65535.f }; -static const XMVECTORF32 g_Scale15pc = { 32767.f, 32767.f, 32767.f, 32767.f }; -static const XMVECTORF32 g_Scale10pc = { 1023.f, 1023.f, 1023.f, 3.f }; -static const XMVECTORF32 g_Scale9pc = { 511.f, 511.f, 511.f, 3.f }; -static const XMVECTORF32 g_Scale8pc = { 255.f, 255.f, 255.f, 255.f }; -static const XMVECTORF32 g_Scale7pc = { 127.f, 127.f, 127.f, 127.f }; -static const XMVECTORF32 g_Scale565pc = { 31.f, 63.f, 31.f, 1.f }; -static const XMVECTORF32 g_Scale5551pc = { 31.f, 31.f, 31.f, 1.f }; -static const XMVECTORF32 g_Scale4pc = { 15.f, 15.f, 15.f, 15.f }; + const XMVECTORF32 g_Scale16pc = { 65535.f, 65535.f, 65535.f, 65535.f }; + const XMVECTORF32 g_Scale15pc = { 32767.f, 32767.f, 32767.f, 32767.f }; + const XMVECTORF32 g_Scale10pc = { 1023.f, 1023.f, 1023.f, 3.f }; + const XMVECTORF32 g_Scale9pc = { 511.f, 511.f, 511.f, 3.f }; + const XMVECTORF32 g_Scale8pc = { 255.f, 255.f, 255.f, 255.f }; + const XMVECTORF32 g_Scale7pc = { 127.f, 127.f, 127.f, 127.f }; + const XMVECTORF32 g_Scale565pc = { 31.f, 63.f, 31.f, 1.f }; + const XMVECTORF32 g_Scale5551pc = { 31.f, 31.f, 31.f, 1.f }; + const XMVECTORF32 g_Scale4pc = { 15.f, 15.f, 15.f, 15.f }; -static const XMVECTORF32 g_ErrorWeight3 = { 3.f/16.f, 3.f/16.f, 3.f/16.f, 3.f/16.f }; -static const XMVECTORF32 g_ErrorWeight5 = { 5.f/16.f, 5.f/16.f, 5.f/16.f, 5.f/16.f }; -static const XMVECTORF32 g_ErrorWeight1 = { 1.f/16.f, 1.f/16.f, 1.f/16.f, 1.f/16.f }; -static const XMVECTORF32 g_ErrorWeight7 = { 7.f/16.f, 7.f/16.f, 7.f/16.f, 7.f/16.f }; + const XMVECTORF32 g_ErrorWeight3 = { 3.f / 16.f, 3.f / 16.f, 3.f / 16.f, 3.f / 16.f }; + const XMVECTORF32 g_ErrorWeight5 = { 5.f / 16.f, 5.f / 16.f, 5.f / 16.f, 5.f / 16.f }; + const XMVECTORF32 g_ErrorWeight1 = { 1.f / 16.f, 1.f / 16.f, 1.f / 16.f, 1.f / 16.f }; + const XMVECTORF32 g_ErrorWeight7 = { 7.f / 16.f, 7.f / 16.f, 7.f / 16.f, 7.f / 16.f }; #define STORE_SCANLINE( type, scalev, clampzero, norm, itype, mask, row, bgr ) \ if ( size >= sizeof(type) ) \ @@ -3659,20 +3703,29 @@ static const XMVECTORF32 g_ErrorWeight7 = { 7.f/16.f, 7.f/16.f, 7.f/16.f, 7.f/16 return true; \ } \ return false; +} #pragma warning(push) #pragma warning( disable : 4127 ) _Use_decl_annotations_ -bool _StoreScanlineDither( LPVOID pDestination, size_t size, DXGI_FORMAT format, - XMVECTOR* pSource, size_t count, float threshold, size_t y, size_t z, XMVECTOR* pDiffusionErrors ) +bool DirectX::_StoreScanlineDither( + void* pDestination, + size_t size, + DXGI_FORMAT format, + XMVECTOR* pSource, + size_t count, + float threshold, + size_t y, + size_t z, + XMVECTOR* pDiffusionErrors) { - assert( pDestination && size > 0 ); - assert( pSource && count > 0 && (((uintptr_t)pSource & 0xF) == 0) ); - assert( IsValid(format) && !IsTypeless(format) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format) ); + assert(pDestination && size > 0); + assert(pSource && count > 0 && (((uintptr_t)pSource & 0xF) == 0)); + assert(IsValid(format) && !IsTypeless(format) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format)); XMVECTOR ordered[4]; - if ( pDiffusionErrors ) + if (pDiffusionErrors) { // If pDiffusionErrors != 0, then this function performs error diffusion dithering (aka Floyd-Steinberg dithering) @@ -3681,102 +3734,102 @@ bool _StoreScanlineDither( LPVOID pDestination, size_t size, DXGI_FORMAT format, XMVECTOR* ptr = pSource; const XMVECTOR* err = pDiffusionErrors + 1; - for( size_t i=0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { // Add contribution from previous scanline - XMVECTOR v = XMVectorAdd( *ptr, *err++ ); + XMVECTOR v = XMVectorAdd(*ptr, *err++); *ptr++ = v; } // Reset errors for next scanline - memset( pDiffusionErrors, 0, sizeof(XMVECTOR)*(count+2) ); + memset(pDiffusionErrors, 0, sizeof(XMVECTOR)*(count + 2)); } else { // If pDiffusionErrors == 0, then this function performs ordered dithering - XMVECTOR dither = XMLoadFloat4( reinterpret_cast( g_Dither + (z & 3) + ( (y & 3) * 8 ) ) ); + XMVECTOR dither = XMLoadFloat4(reinterpret_cast(g_Dither + (z & 3) + ((y & 3) * 8))); - ordered[0] = XMVectorSplatX( dither ); - ordered[1] = XMVectorSplatY( dither ); - ordered[2] = XMVectorSplatZ( dither ); - ordered[3] = XMVectorSplatW( dither ); + ordered[0] = XMVectorSplatX(dither); + ordered[1] = XMVectorSplatY(dither); + ordered[2] = XMVectorSplatZ(dither); + ordered[3] = XMVectorSplatW(dither); } const XMVECTOR* __restrict sPtr = pSource; - if ( !sPtr ) + if (!sPtr) return false; XMVECTOR vError = XMVectorZero(); - switch( static_cast(format) ) + switch (static_cast(format)) { case DXGI_FORMAT_R16G16B16A16_UNORM: - STORE_SCANLINE( XMUSHORTN4, g_Scale16pc, true, true, uint16_t, 0xFFFF, y, false ) + STORE_SCANLINE(XMUSHORTN4, g_Scale16pc, true, true, uint16_t, 0xFFFF, y, false) case DXGI_FORMAT_R16G16B16A16_UINT: - STORE_SCANLINE( XMUSHORT4, g_Scale16pc, true, false, uint16_t, 0xFFFF, y, false ) + STORE_SCANLINE(XMUSHORT4, g_Scale16pc, true, false, uint16_t, 0xFFFF, y, false) case DXGI_FORMAT_R16G16B16A16_SNORM: - STORE_SCANLINE( XMSHORTN4, g_Scale15pc, false, true, int16_t, 0xFFFF, y, false ) + STORE_SCANLINE(XMSHORTN4, g_Scale15pc, false, true, int16_t, 0xFFFF, y, false) case DXGI_FORMAT_R16G16B16A16_SINT: - STORE_SCANLINE( XMSHORT4, g_Scale15pc, false, false, int16_t, 0xFFFF, y, false ) + STORE_SCANLINE(XMSHORT4, g_Scale15pc, false, false, int16_t, 0xFFFF, y, false) case DXGI_FORMAT_R10G10B10A2_UNORM: - STORE_SCANLINE( XMUDECN4, g_Scale10pc, true, true, uint16_t, 0x3FF, y, false ) + STORE_SCANLINE(XMUDECN4, g_Scale10pc, true, true, uint16_t, 0x3FF, y, false) case DXGI_FORMAT_R10G10B10A2_UINT: - STORE_SCANLINE( XMUDEC4, g_Scale10pc, true, false, uint16_t, 0x3FF, y, false ) + STORE_SCANLINE(XMUDEC4, g_Scale10pc, true, false, uint16_t, 0x3FF, y, false) case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: - if ( size >= sizeof(XMUDEC4) ) + if (size >= sizeof(XMUDEC4)) { static const XMVECTORF32 Scale = { 510.0f, 510.0f, 510.0f, 3.0f }; - static const XMVECTORF32 Bias = { 384.0f, 384.0f, 384.0f, 0.0f }; + static const XMVECTORF32 Bias = { 384.0f, 384.0f, 384.0f, 0.0f }; static const XMVECTORF32 MinXR = { -0.7529f, -0.7529f, -0.7529f, 0.f }; static const XMVECTORF32 MaxXR = { 1.2529f, 1.2529f, 1.2529f, 1.0f }; XMUDEC4 * __restrict dest = reinterpret_cast(pDestination); - for( size_t i = 0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { - ptrdiff_t index = static_cast( ( y & 1 ) ? ( count - i - 1 ) : i ); - ptrdiff_t delta = ( y & 1 ) ? -2 : 0; + ptrdiff_t index = static_cast((y & 1) ? (count - i - 1) : i); + ptrdiff_t delta = (y & 1) ? -2 : 0; - XMVECTOR v = XMVectorClamp( sPtr[ index ], MinXR, MaxXR ); - v = XMVectorMultiplyAdd( v, Scale, vError ); + XMVECTOR v = XMVectorClamp(sPtr[index], MinXR, MaxXR); + v = XMVectorMultiplyAdd(v, Scale, vError); XMVECTOR target; - if ( pDiffusionErrors ) + if (pDiffusionErrors) { - target = XMVectorRound( v ); - vError = XMVectorSubtract( v, target ); - vError = XMVectorDivide( vError, Scale ); + target = XMVectorRound(v); + vError = XMVectorSubtract(v, target); + vError = XMVectorDivide(vError, Scale); // Distribute error to next scanline and next pixel - pDiffusionErrors[ index-delta ] += XMVectorMultiply( g_ErrorWeight3, vError ); - pDiffusionErrors[ index+1 ] += XMVectorMultiply( g_ErrorWeight5, vError ); - pDiffusionErrors[ index+2+delta ] += XMVectorMultiply( g_ErrorWeight1, vError ); - vError = XMVectorMultiply( vError, g_ErrorWeight7 ); + pDiffusionErrors[index - delta] += XMVectorMultiply(g_ErrorWeight3, vError); + pDiffusionErrors[index + 1] += XMVectorMultiply(g_ErrorWeight5, vError); + pDiffusionErrors[index + 2 + delta] += XMVectorMultiply(g_ErrorWeight1, vError); + vError = XMVectorMultiply(vError, g_ErrorWeight7); } else { // Applied ordered dither - target = XMVectorAdd( v, ordered[ index & 3 ] ); - target = XMVectorRound( target ); + target = XMVectorAdd(v, ordered[index & 3]); + target = XMVectorRound(target); } - target = XMVectorAdd( target, Bias ); - target = XMVectorClamp( target, g_XMZero, g_Scale10pc ); + target = XMVectorAdd(target, Bias); + target = XMVectorClamp(target, g_XMZero, g_Scale10pc); XMFLOAT4A tmp; - XMStoreFloat4A( &tmp, target ); + XMStoreFloat4A(&tmp, target); - auto dPtr = &dest[ index ]; - dPtr->x = static_cast( tmp.x ) & 0x3FF; - dPtr->y = static_cast( tmp.y ) & 0x3FF; - dPtr->z = static_cast( tmp.z ) & 0x3FF; - dPtr->w = static_cast( tmp.w ); + auto dPtr = &dest[index]; + dPtr->x = static_cast(tmp.x) & 0x3FF; + dPtr->y = static_cast(tmp.y) & 0x3FF; + dPtr->z = static_cast(tmp.z) & 0x3FF; + dPtr->w = static_cast(tmp.w); } return true; } @@ -3784,211 +3837,211 @@ bool _StoreScanlineDither( LPVOID pDestination, size_t size, DXGI_FORMAT format, case DXGI_FORMAT_R8G8B8A8_UNORM: case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - STORE_SCANLINE( XMUBYTEN4, g_Scale8pc, true, true, uint8_t, 0xFF, y, false ) + STORE_SCANLINE(XMUBYTEN4, g_Scale8pc, true, true, uint8_t, 0xFF, y, false) case DXGI_FORMAT_R8G8B8A8_UINT: - STORE_SCANLINE( XMUBYTE4, g_Scale8pc, true, false, uint8_t, 0xFF, y, false ) + STORE_SCANLINE(XMUBYTE4, g_Scale8pc, true, false, uint8_t, 0xFF, y, false) case DXGI_FORMAT_R8G8B8A8_SNORM: - STORE_SCANLINE( XMBYTEN4, g_Scale7pc, false, true, int8_t, 0xFF, y, false ) + STORE_SCANLINE(XMBYTEN4, g_Scale7pc, false, true, int8_t, 0xFF, y, false) case DXGI_FORMAT_R8G8B8A8_SINT: - STORE_SCANLINE( XMBYTE4, g_Scale7pc, false, false, int8_t, 0xFF, y, false ) + STORE_SCANLINE(XMBYTE4, g_Scale7pc, false, false, int8_t, 0xFF, y, false) case DXGI_FORMAT_R16G16_UNORM: - STORE_SCANLINE2( XMUSHORTN2, g_Scale16pc, true, true, uint16_t, 0xFFFF, y ) + STORE_SCANLINE2(XMUSHORTN2, g_Scale16pc, true, true, uint16_t, 0xFFFF, y) case DXGI_FORMAT_R16G16_UINT: - STORE_SCANLINE2( XMUSHORT2, g_Scale16pc, true, false, uint16_t, 0xFFFF, y ) + STORE_SCANLINE2(XMUSHORT2, g_Scale16pc, true, false, uint16_t, 0xFFFF, y) case DXGI_FORMAT_R16G16_SNORM: - STORE_SCANLINE2( XMSHORTN2, g_Scale15pc, false, true, int16_t, 0xFFFF, y ) + STORE_SCANLINE2(XMSHORTN2, g_Scale15pc, false, true, int16_t, 0xFFFF, y) case DXGI_FORMAT_R16G16_SINT: - STORE_SCANLINE2( XMSHORT2, g_Scale15pc, false, false, int16_t, 0xFFFF, y ) + STORE_SCANLINE2(XMSHORT2, g_Scale15pc, false, false, int16_t, 0xFFFF, y) case DXGI_FORMAT_D24_UNORM_S8_UINT: - if ( size >= sizeof(uint32_t) ) + if (size >= sizeof(uint32_t)) { - static const XMVECTORF32 Clamp = { 1.f, 255.f, 0.f, 0.f }; - static const XMVECTORF32 Scale = { 16777215.f, 1.f, 0.f, 0.f }; + static const XMVECTORF32 Clamp = { 1.f, 255.f, 0.f, 0.f }; + static const XMVECTORF32 Scale = { 16777215.f, 1.f, 0.f, 0.f }; static const XMVECTORF32 Scale2 = { 16777215.f, 255.f, 0.f, 0.f }; uint32_t * __restrict dest = reinterpret_cast(pDestination); - for( size_t i = 0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { - ptrdiff_t index = static_cast( ( y & 1 ) ? ( count - i - 1 ) : i ); - ptrdiff_t delta = ( y & 1 ) ? -2 : 0; + ptrdiff_t index = static_cast((y & 1) ? (count - i - 1) : i); + ptrdiff_t delta = (y & 1) ? -2 : 0; - XMVECTOR v = XMVectorClamp( sPtr[ index ], g_XMZero, Clamp ); - v = XMVectorAdd( v, vError ); - v = XMVectorMultiply( v, Scale ); + XMVECTOR v = XMVectorClamp(sPtr[index], g_XMZero, Clamp); + v = XMVectorAdd(v, vError); + v = XMVectorMultiply(v, Scale); XMVECTOR target; - if ( pDiffusionErrors ) + if (pDiffusionErrors) { - target = XMVectorRound( v ); - vError = XMVectorSubtract( v, target ); - vError = XMVectorDivide( vError, Scale ); + target = XMVectorRound(v); + vError = XMVectorSubtract(v, target); + vError = XMVectorDivide(vError, Scale); // Distribute error to next scanline and next pixel - pDiffusionErrors[ index-delta ] += XMVectorMultiply( g_ErrorWeight3, vError ); - pDiffusionErrors[ index+1 ] += XMVectorMultiply( g_ErrorWeight5, vError ); - pDiffusionErrors[ index+2+delta ] += XMVectorMultiply( g_ErrorWeight1, vError ); - vError = XMVectorMultiply( vError, g_ErrorWeight7 ); + pDiffusionErrors[index - delta] += XMVectorMultiply(g_ErrorWeight3, vError); + pDiffusionErrors[index + 1] += XMVectorMultiply(g_ErrorWeight5, vError); + pDiffusionErrors[index + 2 + delta] += XMVectorMultiply(g_ErrorWeight1, vError); + vError = XMVectorMultiply(vError, g_ErrorWeight7); } else { // Applied ordered dither - target = XMVectorAdd( v, ordered[ index & 3 ] ); - target = XMVectorRound( target ); + target = XMVectorAdd(v, ordered[index & 3]); + target = XMVectorRound(target); } - target = XMVectorClamp( target, g_XMZero, Scale2 ); + target = XMVectorClamp(target, g_XMZero, Scale2); XMFLOAT4A tmp; - XMStoreFloat4A( &tmp, target ); + XMStoreFloat4A(&tmp, target); - auto dPtr = &dest[ index ]; - *dPtr = (static_cast( tmp.x ) & 0xFFFFFF) - | ((static_cast( tmp.y ) & 0xFF) << 24); + auto dPtr = &dest[index]; + *dPtr = (static_cast(tmp.x) & 0xFFFFFF) + | ((static_cast(tmp.y) & 0xFF) << 24); } return true; } return false; case DXGI_FORMAT_R8G8_UNORM: - STORE_SCANLINE2( XMUBYTEN2, g_Scale8pc, true, true, uint8_t, 0xFF, y ) + STORE_SCANLINE2(XMUBYTEN2, g_Scale8pc, true, true, uint8_t, 0xFF, y) case DXGI_FORMAT_R8G8_UINT: - STORE_SCANLINE2( XMUBYTE2, g_Scale8pc, true, false, uint8_t, 0xFF, y ) + STORE_SCANLINE2(XMUBYTE2, g_Scale8pc, true, false, uint8_t, 0xFF, y) case DXGI_FORMAT_R8G8_SNORM: - STORE_SCANLINE2( XMBYTEN2, g_Scale7pc, false, true, int8_t, 0xFF, y ) + STORE_SCANLINE2(XMBYTEN2, g_Scale7pc, false, true, int8_t, 0xFF, y) case DXGI_FORMAT_R8G8_SINT: - STORE_SCANLINE2( XMBYTE2, g_Scale7pc, false, false, int8_t, 0xFF, y ) + STORE_SCANLINE2(XMBYTE2, g_Scale7pc, false, false, int8_t, 0xFF, y) case DXGI_FORMAT_D16_UNORM: case DXGI_FORMAT_R16_UNORM: - STORE_SCANLINE1( uint16_t, g_Scale16pc, true, true, 0xFFFF, y, false ) + STORE_SCANLINE1(uint16_t, g_Scale16pc, true, true, 0xFFFF, y, false) case DXGI_FORMAT_R16_UINT: - STORE_SCANLINE1( uint16_t, g_Scale16pc, true, false, 0xFFFF, y, false ) + STORE_SCANLINE1(uint16_t, g_Scale16pc, true, false, 0xFFFF, y, false) case DXGI_FORMAT_R16_SNORM: - STORE_SCANLINE1( int16_t, g_Scale15pc, false, true, 0xFFFF, y, false ) + STORE_SCANLINE1(int16_t, g_Scale15pc, false, true, 0xFFFF, y, false) case DXGI_FORMAT_R16_SINT: - STORE_SCANLINE1( int16_t, g_Scale15pc, false, false, 0xFFFF, y, false ) + STORE_SCANLINE1(int16_t, g_Scale15pc, false, false, 0xFFFF, y, false) case DXGI_FORMAT_R8_UNORM: - STORE_SCANLINE1( uint8_t, g_Scale8pc, true, true, 0xFF, y, false ) + STORE_SCANLINE1(uint8_t, g_Scale8pc, true, true, 0xFF, y, false) case DXGI_FORMAT_R8_UINT: - STORE_SCANLINE1( uint8_t, g_Scale8pc, true, false, 0xFF, y, false ) + STORE_SCANLINE1(uint8_t, g_Scale8pc, true, false, 0xFF, y, false) case DXGI_FORMAT_R8_SNORM: - STORE_SCANLINE1( int8_t, g_Scale7pc, false, true, 0xFF, y, false ) + STORE_SCANLINE1(int8_t, g_Scale7pc, false, true, 0xFF, y, false) case DXGI_FORMAT_R8_SINT: - STORE_SCANLINE1( int8_t, g_Scale7pc, false, false, 0xFF, y, false ) + STORE_SCANLINE1(int8_t, g_Scale7pc, false, false, 0xFF, y, false) case DXGI_FORMAT_A8_UNORM: - STORE_SCANLINE1( uint8_t, g_Scale8pc, true, true, 0xFF, y, true ) + STORE_SCANLINE1(uint8_t, g_Scale8pc, true, true, 0xFF, y, true) case DXGI_FORMAT_B5G6R5_UNORM: - if ( size >= sizeof(XMU565) ) + if (size >= sizeof(XMU565)) { XMU565 * __restrict dest = reinterpret_cast(pDestination); - for( size_t i = 0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { - ptrdiff_t index = static_cast( ( y & 1 ) ? ( count - i - 1 ) : i ); - ptrdiff_t delta = ( y & 1 ) ? -2 : 0; + ptrdiff_t index = static_cast((y & 1) ? (count - i - 1) : i); + ptrdiff_t delta = (y & 1) ? -2 : 0; - XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>( sPtr[ index ] ); - v = XMVectorSaturate( v ); - v = XMVectorAdd( v, vError ); - v = XMVectorMultiply( v, g_Scale565pc ); + XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(sPtr[index]); + v = XMVectorSaturate(v); + v = XMVectorAdd(v, vError); + v = XMVectorMultiply(v, g_Scale565pc); XMVECTOR target; - if ( pDiffusionErrors ) + if (pDiffusionErrors) { - target = XMVectorRound( v ); - vError = XMVectorSubtract( v, target ); - vError = XMVectorDivide( vError, g_Scale565pc ); + target = XMVectorRound(v); + vError = XMVectorSubtract(v, target); + vError = XMVectorDivide(vError, g_Scale565pc); // Distribute error to next scanline and next pixel - pDiffusionErrors[ index-delta ] += XMVectorMultiply( g_ErrorWeight3, vError ); - pDiffusionErrors[ index+1 ] += XMVectorMultiply( g_ErrorWeight5, vError ); - pDiffusionErrors[ index+2+delta ] += XMVectorMultiply( g_ErrorWeight1, vError ); - vError = XMVectorMultiply( vError, g_ErrorWeight7 ); + pDiffusionErrors[index - delta] += XMVectorMultiply(g_ErrorWeight3, vError); + pDiffusionErrors[index + 1] += XMVectorMultiply(g_ErrorWeight5, vError); + pDiffusionErrors[index + 2 + delta] += XMVectorMultiply(g_ErrorWeight1, vError); + vError = XMVectorMultiply(vError, g_ErrorWeight7); } else { // Applied ordered dither - target = XMVectorAdd( v, ordered[ index & 3 ] ); - target = XMVectorRound( target ); + target = XMVectorAdd(v, ordered[index & 3]); + target = XMVectorRound(target); } - target = XMVectorClamp( target, g_XMZero, g_Scale565pc ); + target = XMVectorClamp(target, g_XMZero, g_Scale565pc); XMFLOAT4A tmp; - XMStoreFloat4A( &tmp, target ); + XMStoreFloat4A(&tmp, target); - auto dPtr = &dest[ index ]; - dPtr->x = static_cast( tmp.x ) & 0x1F; - dPtr->y = static_cast( tmp.y ) & 0x3F; - dPtr->z = static_cast( tmp.z ) & 0x1F; + auto dPtr = &dest[index]; + dPtr->x = static_cast(tmp.x) & 0x1F; + dPtr->y = static_cast(tmp.y) & 0x3F; + dPtr->z = static_cast(tmp.z) & 0x1F; } return true; } return false; case DXGI_FORMAT_B5G5R5A1_UNORM: - if ( size >= sizeof(XMU555) ) + if (size >= sizeof(XMU555)) { XMU555 * __restrict dest = reinterpret_cast(pDestination); - for( size_t i = 0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { - ptrdiff_t index = static_cast( ( y & 1 ) ? ( count - i - 1 ) : i ); - ptrdiff_t delta = ( y & 1 ) ? -2 : 0; + ptrdiff_t index = static_cast((y & 1) ? (count - i - 1) : i); + ptrdiff_t delta = (y & 1) ? -2 : 0; - XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>( sPtr[ index ] ); - v = XMVectorSaturate( v ); - v = XMVectorAdd( v, vError ); - v = XMVectorMultiply( v, g_Scale5551pc ); + XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(sPtr[index]); + v = XMVectorSaturate(v); + v = XMVectorAdd(v, vError); + v = XMVectorMultiply(v, g_Scale5551pc); XMVECTOR target; - if ( pDiffusionErrors ) + if (pDiffusionErrors) { - target = XMVectorRound( v ); - vError = XMVectorSubtract( v, target ); - vError = XMVectorDivide( vError, g_Scale5551pc ); + target = XMVectorRound(v); + vError = XMVectorSubtract(v, target); + vError = XMVectorDivide(vError, g_Scale5551pc); // Distribute error to next scanline and next pixel - pDiffusionErrors[ index-delta ] += XMVectorMultiply( g_ErrorWeight3, vError ); - pDiffusionErrors[ index+1 ] += XMVectorMultiply( g_ErrorWeight5, vError ); - pDiffusionErrors[ index+2+delta ] += XMVectorMultiply( g_ErrorWeight1, vError ); - vError = XMVectorMultiply( vError, g_ErrorWeight7 ); + pDiffusionErrors[index - delta] += XMVectorMultiply(g_ErrorWeight3, vError); + pDiffusionErrors[index + 1] += XMVectorMultiply(g_ErrorWeight5, vError); + pDiffusionErrors[index + 2 + delta] += XMVectorMultiply(g_ErrorWeight1, vError); + vError = XMVectorMultiply(vError, g_ErrorWeight7); } else { // Applied ordered dither - target = XMVectorAdd( v, ordered[ index & 3 ] ); - target = XMVectorRound( target ); + target = XMVectorAdd(v, ordered[index & 3]); + target = XMVectorRound(target); } - target = XMVectorClamp( target, g_XMZero, g_Scale5551pc ); + target = XMVectorClamp(target, g_XMZero, g_Scale5551pc); XMFLOAT4A tmp; - XMStoreFloat4A( &tmp, target ); + XMStoreFloat4A(&tmp, target); - auto dPtr = &dest[ index ]; - dPtr->x = static_cast( tmp.x ) & 0x1F; - dPtr->y = static_cast( tmp.y ) & 0x1F; - dPtr->z = static_cast( tmp.z ) & 0x1F; - dPtr->w = ( XMVectorGetW( target ) > threshold ) ? 1 : 0; + auto dPtr = &dest[index]; + dPtr->x = static_cast(tmp.x) & 0x1F; + dPtr->y = static_cast(tmp.y) & 0x1F; + dPtr->z = static_cast(tmp.z) & 0x1F; + dPtr->w = (XMVectorGetW(target) > threshold) ? 1 : 0; } return true; } @@ -3996,52 +4049,52 @@ bool _StoreScanlineDither( LPVOID pDestination, size_t size, DXGI_FORMAT format, case DXGI_FORMAT_B8G8R8A8_UNORM: case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: - STORE_SCANLINE( XMUBYTEN4, g_Scale8pc, true, true, uint8_t, 0xFF, y, true ) + STORE_SCANLINE(XMUBYTEN4, g_Scale8pc, true, true, uint8_t, 0xFF, y, true) case DXGI_FORMAT_B8G8R8X8_UNORM: case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: - if ( size >= sizeof(XMUBYTEN4) ) + if (size >= sizeof(XMUBYTEN4)) { XMUBYTEN4 * __restrict dest = reinterpret_cast(pDestination); - for( size_t i = 0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { - ptrdiff_t index = static_cast( ( y & 1 ) ? ( count - i - 1 ) : i ); - ptrdiff_t delta = ( y & 1 ) ? -2 : 0; + ptrdiff_t index = static_cast((y & 1) ? (count - i - 1) : i); + ptrdiff_t delta = (y & 1) ? -2 : 0; - XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>( sPtr[ index ] ); - v = XMVectorSaturate( v ); - v = XMVectorAdd( v, vError ); - v = XMVectorMultiply( v, g_Scale8pc ); + XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(sPtr[index]); + v = XMVectorSaturate(v); + v = XMVectorAdd(v, vError); + v = XMVectorMultiply(v, g_Scale8pc); XMVECTOR target; - if ( pDiffusionErrors ) + if (pDiffusionErrors) { - target = XMVectorRound( v ); - vError = XMVectorSubtract( v, target ); - vError = XMVectorDivide( vError, g_Scale8pc ); + target = XMVectorRound(v); + vError = XMVectorSubtract(v, target); + vError = XMVectorDivide(vError, g_Scale8pc); // Distribute error to next scanline and next pixel - pDiffusionErrors[ index-delta ] += XMVectorMultiply( g_ErrorWeight3, vError ); - pDiffusionErrors[ index+1 ] += XMVectorMultiply( g_ErrorWeight5, vError ); - pDiffusionErrors[ index+2+delta ] += XMVectorMultiply( g_ErrorWeight1, vError ); - vError = XMVectorMultiply( vError, g_ErrorWeight7 ); + pDiffusionErrors[index - delta] += XMVectorMultiply(g_ErrorWeight3, vError); + pDiffusionErrors[index + 1] += XMVectorMultiply(g_ErrorWeight5, vError); + pDiffusionErrors[index + 2 + delta] += XMVectorMultiply(g_ErrorWeight1, vError); + vError = XMVectorMultiply(vError, g_ErrorWeight7); } else { // Applied ordered dither - target = XMVectorAdd( v, ordered[ index & 3 ] ); - target = XMVectorRound( target ); + target = XMVectorAdd(v, ordered[index & 3]); + target = XMVectorRound(target); } - target = XMVectorClamp( target, g_XMZero, g_Scale8pc ); + target = XMVectorClamp(target, g_XMZero, g_Scale8pc); XMFLOAT4A tmp; - XMStoreFloat4A( &tmp, target ); + XMStoreFloat4A(&tmp, target); - auto dPtr = &dest[ index ]; - dPtr->x = static_cast( tmp.x ) & 0xFF; - dPtr->y = static_cast( tmp.y ) & 0xFF; - dPtr->z = static_cast( tmp.z ) & 0xFF; + auto dPtr = &dest[index]; + dPtr->x = static_cast(tmp.x) & 0xFF; + dPtr->y = static_cast(tmp.y) & 0xFF; + dPtr->z = static_cast(tmp.z) & 0xFF; dPtr->w = 0; } return true; @@ -4049,58 +4102,58 @@ bool _StoreScanlineDither( LPVOID pDestination, size_t size, DXGI_FORMAT format, return false; case DXGI_FORMAT_B4G4R4A4_UNORM: - STORE_SCANLINE( XMUNIBBLE4, g_Scale4pc, true, true, uint8_t, 0xF, y, true ) + STORE_SCANLINE(XMUNIBBLE4, g_Scale4pc, true, true, uint8_t, 0xF, y, true) case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM: - STORE_SCANLINE( XMXDECN4, g_Scale9pc, false, true, uint16_t, 0x3FF, y, false ) + STORE_SCANLINE(XMXDECN4, g_Scale9pc, false, true, uint16_t, 0x3FF, y, false) case XBOX_DXGI_FORMAT_R4G4_UNORM: - if ( size >= sizeof(uint8_t) ) + if (size >= sizeof(uint8_t)) { uint8_t * __restrict dest = reinterpret_cast(pDestination); - for( size_t i = 0; i < count; ++i ) + for (size_t i = 0; i < count; ++i) { - ptrdiff_t index = static_cast( ( y & 1 ) ? ( count - i - 1 ) : i ); - ptrdiff_t delta = ( y & 1 ) ? -2 : 0; + ptrdiff_t index = static_cast((y & 1) ? (count - i - 1) : i); + ptrdiff_t delta = (y & 1) ? -2 : 0; - XMVECTOR v = XMVectorSaturate( sPtr[ index ] ); - v = XMVectorAdd( v, vError ); - v = XMVectorMultiply( v, g_Scale4pc ); + XMVECTOR v = XMVectorSaturate(sPtr[index]); + v = XMVectorAdd(v, vError); + v = XMVectorMultiply(v, g_Scale4pc); XMVECTOR target; - if ( pDiffusionErrors ) + if (pDiffusionErrors) { - target = XMVectorRound( v ); - vError = XMVectorSubtract( v, target ); - vError = XMVectorDivide( vError, g_Scale4pc ); + target = XMVectorRound(v); + vError = XMVectorSubtract(v, target); + vError = XMVectorDivide(vError, g_Scale4pc); // Distribute error to next scanline and next pixel - pDiffusionErrors[ index-delta ] += XMVectorMultiply( g_ErrorWeight3, vError ); - pDiffusionErrors[ index+1 ] += XMVectorMultiply( g_ErrorWeight5, vError ); - pDiffusionErrors[ index+2+delta ] += XMVectorMultiply( g_ErrorWeight1, vError ); - vError = XMVectorMultiply( vError, g_ErrorWeight7 ); + pDiffusionErrors[index - delta] += XMVectorMultiply(g_ErrorWeight3, vError); + pDiffusionErrors[index + 1] += XMVectorMultiply(g_ErrorWeight5, vError); + pDiffusionErrors[index + 2 + delta] += XMVectorMultiply(g_ErrorWeight1, vError); + vError = XMVectorMultiply(vError, g_ErrorWeight7); } else { // Applied ordered dither - target = XMVectorAdd( v, ordered[ index & 3 ] ); - target = XMVectorRound( target ); + target = XMVectorAdd(v, ordered[index & 3]); + target = XMVectorRound(target); } - target = XMVectorClamp( target, g_XMZero, g_Scale4pc ); + target = XMVectorClamp(target, g_XMZero, g_Scale4pc); XMFLOAT4A tmp; - XMStoreFloat4A( &tmp, target ); + XMStoreFloat4A(&tmp, target); - dest[index] = ( static_cast( tmp.x ) & 0xF ) - | ( ( static_cast( tmp.y ) & 0xF ) << 4 ); + dest[index] = (static_cast(tmp.x) & 0xF) + | ((static_cast(tmp.y) & 0xF) << 4); } return true; } return false; default: - return _StoreScanline( pDestination, size, format, pSource, count, threshold ); + return _StoreScanline(pDestination, size, format, pSource, count, threshold); } } @@ -4110,224 +4163,214 @@ bool _StoreScanlineDither( LPVOID pDestination, size_t size, DXGI_FORMAT format, #undef STORE_SCANLINE2 #undef STORE_SCANLINE1 - -//------------------------------------------------------------------------------------- -// Selection logic for using WIC vs. our own routines -//------------------------------------------------------------------------------------- -static inline bool _UseWICConversion( _In_ DWORD filter, _In_ DXGI_FORMAT sformat, _In_ DXGI_FORMAT tformat, - _Out_ WICPixelFormatGUID& pfGUID, _Out_ WICPixelFormatGUID& targetGUID ) +namespace { - memcpy( &pfGUID, &GUID_NULL, sizeof(GUID) ); - memcpy( &targetGUID, &GUID_NULL, sizeof(GUID) ); - - if ( filter & TEX_FILTER_FORCE_NON_WIC ) + //------------------------------------------------------------------------------------- + // Selection logic for using WIC vs. our own routines + //------------------------------------------------------------------------------------- + inline bool UseWICConversion( + _In_ DWORD filter, + _In_ DXGI_FORMAT sformat, + _In_ DXGI_FORMAT tformat, + _Out_ WICPixelFormatGUID& pfGUID, + _Out_ WICPixelFormatGUID& targetGUID) { - // Explicit flag indicates use of non-WIC code paths - return false; - } + memcpy(&pfGUID, &GUID_NULL, sizeof(GUID)); + memcpy(&targetGUID, &GUID_NULL, sizeof(GUID)); - if ( !_DXGIToWIC( sformat, pfGUID ) || !_DXGIToWIC( tformat, targetGUID ) ) - { - // Source or target format are not WIC supported native pixel formats - return false; - } + if (filter & TEX_FILTER_FORCE_NON_WIC) + { + // Explicit flag indicates use of non-WIC code paths + return false; + } + + if (!_DXGIToWIC(sformat, pfGUID) || !_DXGIToWIC(tformat, targetGUID)) + { + // Source or target format are not WIC supported native pixel formats + return false; + } + + if (filter & TEX_FILTER_FORCE_WIC) + { + // Explicit flag to use WIC code paths, skips all the case checks below + return true; + } + + if (filter & TEX_FILTER_SEPARATE_ALPHA) + { + // Alpha is not premultiplied, so use non-WIC code paths + return false; + } + +#if defined(_XBOX_ONE) && defined(_TITLE) + if (sformat == DXGI_FORMAT_R16G16B16A16_FLOAT + || sformat == DXGI_FORMAT_R16_FLOAT + || tformat == DXGI_FORMAT_R16G16B16A16_FLOAT + || tformat == DXGI_FORMAT_R16_FLOAT) + { + // Use non-WIC code paths as these conversions are not supported by Xbox One XDK + return false; + } +#endif + + // Check for special cases + switch (sformat) + { + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + switch (tformat) + { + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_D32_FLOAT: + // WIC converts via UNORM formats and ends up converting colorspaces for these cases + case DXGI_FORMAT_A8_UNORM: + // Conversion logic for these kinds of textures is unintuitive for WIC code paths + return false; + } + break; + + case DXGI_FORMAT_R16_FLOAT: + switch (tformat) + { + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_D32_FLOAT: + // WIC converts via UNORM formats and ends up converting colorspaces for these cases + case DXGI_FORMAT_A8_UNORM: + // Conversion logic for these kinds of textures is unintuitive for WIC code paths + return false; + } + break; + + case DXGI_FORMAT_A8_UNORM: + // Conversion logic for these kinds of textures is unintuitive for WIC code paths + return false; + + default: + switch (tformat) + { + case DXGI_FORMAT_A8_UNORM: + // Conversion logic for these kinds of textures is unintuitive for WIC code paths + return false; + } + } + + // Check for implicit color space changes + if (IsSRGB(sformat)) + filter |= TEX_FILTER_SRGB_IN; + + if (IsSRGB(tformat)) + filter |= TEX_FILTER_SRGB_OUT; + + if ((filter & (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT)) == (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT)) + { + filter &= ~(TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT); + } + + DWORD wicsrgb = _CheckWICColorSpace(pfGUID, targetGUID); + + if (wicsrgb != (filter & (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT))) + { + // WIC will perform a colorspace conversion we didn't request + return false; + } - if ( filter & TEX_FILTER_FORCE_WIC ) - { - // Explicit flag to use WIC code paths, skips all the case checks below return true; } - if ( filter & TEX_FILTER_SEPARATE_ALPHA ) + //------------------------------------------------------------------------------------- + // Convert the source image using WIC + //------------------------------------------------------------------------------------- + HRESULT ConvertUsingWIC( + _In_ const Image& srcImage, + _In_ const WICPixelFormatGUID& pfGUID, + _In_ const WICPixelFormatGUID& targetGUID, + _In_ DWORD filter, + _In_ float threshold, + _In_ const Image& destImage) { - // Alpha is not premultiplied, so use non-WIC code paths - return false; - } + assert(srcImage.width == destImage.width); + assert(srcImage.height == destImage.height); -#if defined(_XBOX_ONE) && defined(_TITLE) - if ( sformat == DXGI_FORMAT_R16G16B16A16_FLOAT - || sformat == DXGI_FORMAT_R16_FLOAT - || tformat == DXGI_FORMAT_R16G16B16A16_FLOAT - || tformat == DXGI_FORMAT_R16_FLOAT ) - { - // Use non-WIC code paths as these conversions are not supported by Xbox One XDK - return false; - } -#endif + bool iswic2 = false; + IWICImagingFactory* pWIC = GetWICFactory(iswic2); + if (!pWIC) + return E_NOINTERFACE; - // Check for special cases - switch ( sformat ) - { - case DXGI_FORMAT_R32G32B32A32_FLOAT: - case DXGI_FORMAT_R32G32B32_FLOAT: - case DXGI_FORMAT_R16G16B16A16_FLOAT: - switch( tformat ) + ComPtr FC; + HRESULT hr = pWIC->CreateFormatConverter(FC.GetAddressOf()); + if (FAILED(hr)) + return hr; + + // Note that WIC conversion ignores the TEX_FILTER_SRGB_IN and TEX_FILTER_SRGB_OUT flags, + // but also always assumes UNORM <-> FLOAT conversions are changing color spaces sRGB <-> scRGB + + BOOL canConvert = FALSE; + hr = FC->CanConvert(pfGUID, targetGUID, &canConvert); + if (FAILED(hr) || !canConvert) { - case DXGI_FORMAT_R16_FLOAT: - case DXGI_FORMAT_R32_FLOAT: - case DXGI_FORMAT_D32_FLOAT: - // WIC converts via UNORM formats and ends up converting colorspaces for these cases - case DXGI_FORMAT_A8_UNORM: - // Conversion logic for these kinds of textures is unintuitive for WIC code paths - return false; + // This case is not an issue for the subset of WIC formats that map directly to DXGI + return E_UNEXPECTED; } - break; - - case DXGI_FORMAT_R16_FLOAT: - switch( tformat ) + + ComPtr source; + hr = pWIC->CreateBitmapFromMemory(static_cast(srcImage.width), static_cast(srcImage.height), pfGUID, + static_cast(srcImage.rowPitch), static_cast(srcImage.slicePitch), + srcImage.pixels, source.GetAddressOf()); + if (FAILED(hr)) + return hr; + + hr = FC->Initialize(source.Get(), targetGUID, _GetWICDither(filter), 0, threshold * 100.f, WICBitmapPaletteTypeCustom); + if (FAILED(hr)) + return hr; + + hr = FC->CopyPixels(0, static_cast(destImage.rowPitch), static_cast(destImage.slicePitch), destImage.pixels); + if (FAILED(hr)) + return hr; + + return S_OK; + } + + + //------------------------------------------------------------------------------------- + // Convert the source image (not using WIC) + //------------------------------------------------------------------------------------- + HRESULT ConvertCustom( + _In_ const Image& srcImage, + _In_ DWORD filter, + _In_ const Image& destImage, + _In_ float threshold, + size_t z) + { + 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; + + size_t width = srcImage.width; + + if (filter & TEX_FILTER_DITHER_DIFFUSION) { - case DXGI_FORMAT_R32_FLOAT: - case DXGI_FORMAT_D32_FLOAT: - // WIC converts via UNORM formats and ends up converting colorspaces for these cases - case DXGI_FORMAT_A8_UNORM: - // Conversion logic for these kinds of textures is unintuitive for WIC code paths - return false; - } - break; + // Error diffusion dithering (aka Floyd-Steinberg dithering) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc((sizeof(XMVECTOR)*(width * 2 + 2)), 16))); + if (!scanline) + return E_OUTOFMEMORY; - case DXGI_FORMAT_A8_UNORM: - // Conversion logic for these kinds of textures is unintuitive for WIC code paths - return false; + XMVECTOR* pDiffusionErrors = scanline.get() + width; + memset(pDiffusionErrors, 0, sizeof(XMVECTOR)*(width + 2)); - default: - switch( tformat ) - { - case DXGI_FORMAT_A8_UNORM: - // Conversion logic for these kinds of textures is unintuitive for WIC code paths - return false; - } - } - - // Check for implicit color space changes - if ( IsSRGB( sformat ) ) - filter |= TEX_FILTER_SRGB_IN; - - if ( IsSRGB( tformat ) ) - filter |= TEX_FILTER_SRGB_OUT; - - if ( (filter & (TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT)) == (TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT) ) - { - filter &= ~(TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT); - } - - DWORD wicsrgb = _CheckWICColorSpace( pfGUID, targetGUID ); - - if ( wicsrgb != (filter & (TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT)) ) - { - // WIC will perform a colorspace conversion we didn't request - return false; - } - - return true; -} - - -//------------------------------------------------------------------------------------- -// Convert the source image using WIC -//------------------------------------------------------------------------------------- -static HRESULT _ConvertUsingWIC( _In_ const Image& srcImage, _In_ const WICPixelFormatGUID& pfGUID, - _In_ const WICPixelFormatGUID& targetGUID, - _In_ DWORD filter, _In_ float threshold, _In_ const Image& destImage ) -{ - assert( srcImage.width == destImage.width ); - assert( srcImage.height == destImage.height ); - - bool iswic2 = false; - IWICImagingFactory* pWIC = GetWICFactory(iswic2); - if ( !pWIC ) - return E_NOINTERFACE; - - ComPtr FC; - HRESULT hr = pWIC->CreateFormatConverter( FC.GetAddressOf() ); - if ( FAILED(hr) ) - return hr; - - // Note that WIC conversion ignores the TEX_FILTER_SRGB_IN and TEX_FILTER_SRGB_OUT flags, - // but also always assumes UNORM <-> FLOAT conversions are changing color spaces sRGB <-> scRGB - - BOOL canConvert = FALSE; - hr = FC->CanConvert( pfGUID, targetGUID, &canConvert ); - if ( FAILED(hr) || !canConvert ) - { - // This case is not an issue for the subset of WIC formats that map directly to DXGI - return E_UNEXPECTED; - } - - ComPtr source; - hr = pWIC->CreateBitmapFromMemory( static_cast( srcImage.width ), static_cast( srcImage.height ), pfGUID, - static_cast( srcImage.rowPitch ), static_cast( srcImage.slicePitch ), - srcImage.pixels, source.GetAddressOf() ); - if ( FAILED(hr) ) - return hr; - - hr = FC->Initialize( source.Get(), targetGUID, _GetWICDither( filter ), 0, threshold * 100.f, WICBitmapPaletteTypeCustom ); - if ( FAILED(hr) ) - return hr; - - hr = FC->CopyPixels( 0, static_cast( destImage.rowPitch ), static_cast( destImage.slicePitch ), destImage.pixels ); - if ( FAILED(hr) ) - return hr; - - return S_OK; -} - - -//------------------------------------------------------------------------------------- -// Convert the source image (not using WIC) -//------------------------------------------------------------------------------------- -static HRESULT _Convert( _In_ const Image& srcImage, _In_ DWORD filter, _In_ const Image& destImage, _In_ float threshold, _In_ size_t z ) -{ - 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; - - size_t width = srcImage.width; - - if ( filter & TEX_FILTER_DITHER_DIFFUSION ) - { - // Error diffusion dithering (aka Floyd-Steinberg dithering) - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( (sizeof(XMVECTOR)*(width*2 + 2)), 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - XMVECTOR* pDiffusionErrors = scanline.get() + width; - memset( pDiffusionErrors, 0, sizeof(XMVECTOR)*(width+2) ); - - for( size_t h = 0; h < srcImage.height; ++h ) - { - if ( !_LoadScanline( scanline.get(), width, pSrc, srcImage.rowPitch, srcImage.format ) ) - return E_FAIL; - - _ConvertScanline( scanline.get(), width, destImage.format, srcImage.format, filter ); - - if ( !_StoreScanlineDither( pDest, destImage.rowPitch, destImage.format, scanline.get(), width, threshold, h, z, pDiffusionErrors ) ) - return E_FAIL; - - pSrc += srcImage.rowPitch; - pDest += destImage.rowPitch; - } - } - else - { - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( (sizeof(XMVECTOR)*width), 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - if ( filter & TEX_FILTER_DITHER ) - { - // Ordered dithering - for( size_t h = 0; h < srcImage.height; ++h ) + for (size_t h = 0; h < srcImage.height; ++h) { - if ( !_LoadScanline( scanline.get(), width, pSrc, srcImage.rowPitch, srcImage.format ) ) + if (!_LoadScanline(scanline.get(), width, pSrc, srcImage.rowPitch, srcImage.format)) return E_FAIL; - _ConvertScanline( scanline.get(), width, destImage.format, srcImage.format, filter ); + _ConvertScanline(scanline.get(), width, destImage.format, srcImage.format, filter); - if ( !_StoreScanlineDither( pDest, destImage.rowPitch, destImage.format, scanline.get(), width, threshold, h, z, nullptr ) ) + if (!_StoreScanlineDither(pDest, destImage.rowPitch, destImage.format, scanline.get(), width, threshold, h, z, pDiffusionErrors)) return E_FAIL; pSrc += srcImage.rowPitch; @@ -4336,57 +4379,78 @@ static HRESULT _Convert( _In_ const Image& srcImage, _In_ DWORD filter, _In_ con } else { - // No dithering - for( size_t h = 0; h < srcImage.height; ++h ) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc((sizeof(XMVECTOR)*width), 16))); + if (!scanline) + return E_OUTOFMEMORY; + + if (filter & TEX_FILTER_DITHER) { - if ( !_LoadScanline( scanline.get(), width, pSrc, srcImage.rowPitch, srcImage.format ) ) - return E_FAIL; + // Ordered dithering + for (size_t h = 0; h < srcImage.height; ++h) + { + if (!_LoadScanline(scanline.get(), width, pSrc, srcImage.rowPitch, srcImage.format)) + return E_FAIL; - _ConvertScanline( scanline.get(), width, destImage.format, srcImage.format, filter ); + _ConvertScanline(scanline.get(), width, destImage.format, srcImage.format, filter); - if ( !_StoreScanline( pDest, destImage.rowPitch, destImage.format, scanline.get(), width, threshold ) ) - return E_FAIL; + if (!_StoreScanlineDither(pDest, destImage.rowPitch, destImage.format, scanline.get(), width, threshold, h, z, nullptr)) + return E_FAIL; - pSrc += srcImage.rowPitch; - pDest += destImage.rowPitch; + pSrc += srcImage.rowPitch; + pDest += destImage.rowPitch; + } } + else + { + // No dithering + for (size_t h = 0; h < srcImage.height; ++h) + { + if (!_LoadScanline(scanline.get(), width, pSrc, srcImage.rowPitch, srcImage.format)) + return E_FAIL; + + _ConvertScanline(scanline.get(), width, destImage.format, srcImage.format, filter); + + if (!_StoreScanline(pDest, destImage.rowPitch, destImage.format, scanline.get(), width, threshold)) + return E_FAIL; + + pSrc += srcImage.rowPitch; + pDest += destImage.rowPitch; + } + } + } + + return S_OK; + } + + //------------------------------------------------------------------------------------- + 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 16-bit depth formats + + // We can't do anything with DXGI_FORMAT_420_OPAQUE because it's an opaque blob of bits + + // We don't support conversion of JPEG Hardware decode formats + + default: + return DXGI_FORMAT_UNKNOWN; } } - return S_OK; -} - - -//------------------------------------------------------------------------------------- -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 16-bit depth formats - - // We can't do anything with DXGI_FORMAT_420_OPAQUE because it's an opaque blob of bits - - // We don't support conversion of JPEG Hardware decode formats - - default: - return DXGI_FORMAT_UNKNOWN; - } -} - - -//------------------------------------------------------------------------------------- -// Convert the image from a planar to non-planar image -//------------------------------------------------------------------------------------- + //------------------------------------------------------------------------------------- + // Convert the image from a planar to non-planar image + //------------------------------------------------------------------------------------- #define CONVERT_420_TO_422( srcType, destType )\ {\ size_t rowPitch = srcImage.rowPitch;\ @@ -4430,83 +4494,84 @@ static DXGI_FORMAT _PlanarToSingle( _In_ DXGI_FORMAT format ) }\ } -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 ) + HRESULT ConvertToSinglePlane_(_In_ const Image& srcImage, _In_ const Image& destImage) { - case DXGI_FORMAT_NV12: - assert( destImage.format == DXGI_FORMAT_YUY2 ); - CONVERT_420_TO_422( uint8_t, XMUBYTEN4 ); - return S_OK; + assert(srcImage.width == destImage.width); + assert(srcImage.height == destImage.height); - case DXGI_FORMAT_P010: - assert( destImage.format == DXGI_FORMAT_Y210 ); - CONVERT_420_TO_422( uint16_t, XMUSHORTN4 ); - return S_OK; + const uint8_t *pSrc = srcImage.pixels; + uint8_t *pDest = destImage.pixels; + if (!pSrc || !pDest) + return E_POINTER; - 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 + switch (srcImage.format) { - 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; + case DXGI_FORMAT_NV12: + assert(destImage.format == DXGI_FORMAT_YUY2); + CONVERT_420_TO_422(uint8_t, XMUBYTEN4); + return S_OK; - default: - return E_UNEXPECTED; + 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 +} //===================================================================================== @@ -4517,45 +4582,50 @@ static HRESULT _ConvertToSinglePlane( _In_ const Image& srcImage, _In_ const Ima // Convert image //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT Convert( const Image& srcImage, DXGI_FORMAT format, DWORD filter, float threshold, ScratchImage& image ) +HRESULT DirectX::Convert( + const Image& srcImage, + DXGI_FORMAT format, + DWORD filter, + float threshold, + ScratchImage& image) { - if ( (srcImage.format == format) || !IsValid( format ) ) + if ((srcImage.format == format) || !IsValid(format)) return E_INVALIDARG; - if ( !srcImage.pixels ) + if (!srcImage.pixels) return E_POINTER; - if ( IsCompressed(srcImage.format) || IsCompressed(format) - || IsPlanar(srcImage.format) || IsPlanar(format) - || IsPalettized(srcImage.format) || IsPalettized(format) - || IsTypeless(srcImage.format) || IsTypeless(format) ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if (IsCompressed(srcImage.format) || IsCompressed(format) + || IsPlanar(srcImage.format) || IsPlanar(format) + || IsPalettized(srcImage.format) || IsPalettized(format) + || IsTypeless(srcImage.format) || IsTypeless(format)) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); - if ( (srcImage.width > UINT32_MAX) || (srcImage.height > UINT32_MAX) ) + if ((srcImage.width > UINT32_MAX) || (srcImage.height > UINT32_MAX)) return E_INVALIDARG; - HRESULT hr = image.Initialize2D( format, srcImage.width, srcImage.height, 1, 1 ); - if ( FAILED(hr) ) + 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 ) + + const Image *rimage = image.GetImage(0, 0, 0); + if (!rimage) { image.Release(); return E_POINTER; } WICPixelFormatGUID pfGUID, targetGUID; - if ( _UseWICConversion( filter, srcImage.format, format, pfGUID, targetGUID ) ) + if (UseWICConversion(filter, srcImage.format, format, pfGUID, targetGUID)) { - hr = _ConvertUsingWIC( srcImage, pfGUID, targetGUID, filter, threshold, *rimage ); + hr = ConvertUsingWIC(srcImage, pfGUID, targetGUID, filter, threshold, *rimage); } else { - hr = _Convert( srcImage, filter, *rimage, threshold, 0 ); + hr = ConvertCustom(srcImage, filter, *rimage, threshold, 0); } - if ( FAILED(hr) ) + if (FAILED(hr)) { image.Release(); return hr; @@ -4569,78 +4639,84 @@ HRESULT Convert( const Image& srcImage, DXGI_FORMAT format, DWORD filter, float // Convert image (complex) //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT Convert( const Image* srcImages, size_t nimages, const TexMetadata& metadata, - DXGI_FORMAT format, DWORD filter, float threshold, ScratchImage& result ) +HRESULT DirectX::Convert( + const Image* srcImages, + size_t nimages, + const TexMetadata& metadata, + DXGI_FORMAT format, + DWORD filter, + float threshold, + ScratchImage& result) { - if ( !srcImages || !nimages || (metadata.format == format) || !IsValid(format) ) + if (!srcImages || !nimages || (metadata.format == format) || !IsValid(format)) return E_INVALIDARG; - if ( IsCompressed(metadata.format) || IsCompressed(format) - || IsPlanar(metadata.format) || IsPlanar(format) - || IsPalettized(metadata.format) || IsPalettized(format) - || IsTypeless(metadata.format) || IsTypeless(format) ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if (IsCompressed(metadata.format) || IsCompressed(format) + || IsPlanar(metadata.format) || IsPlanar(format) + || IsPalettized(metadata.format) || IsPalettized(format) + || IsTypeless(metadata.format) || IsTypeless(format)) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); - if ( (metadata.width > UINT32_MAX) || (metadata.height > UINT32_MAX) ) + if ((metadata.width > UINT32_MAX) || (metadata.height > UINT32_MAX)) return E_INVALIDARG; TexMetadata mdata2 = metadata; mdata2.format = format; - HRESULT hr = result.Initialize( mdata2 ); - if ( FAILED(hr) ) + HRESULT hr = result.Initialize(mdata2); + if (FAILED(hr)) return hr; - if ( nimages != result.GetImageCount() ) + if (nimages != result.GetImageCount()) { result.Release(); return E_FAIL; } const Image* dest = result.GetImages(); - if ( !dest ) + if (!dest) { result.Release(); return E_POINTER; } WICPixelFormatGUID pfGUID, targetGUID; - bool usewic = _UseWICConversion( filter, metadata.format, format, pfGUID, targetGUID ); + bool usewic = UseWICConversion(filter, metadata.format, format, pfGUID, targetGUID); switch (metadata.dimension) { case TEX_DIMENSION_TEXTURE1D: case TEX_DIMENSION_TEXTURE2D: - for( size_t index=0; index < nimages; ++index ) + for (size_t index = 0; index < nimages; ++index) { - const Image& src = srcImages[ index ]; - if ( src.format != metadata.format ) + const Image& src = srcImages[index]; + if (src.format != metadata.format) { result.Release(); return E_FAIL; } - if ( (src.width > UINT32_MAX) || (src.height > UINT32_MAX) ) + if ((src.width > UINT32_MAX) || (src.height > UINT32_MAX)) return E_FAIL; - const Image& dst = dest[ index ]; - assert( dst.format == format ); + const Image& dst = dest[index]; + assert(dst.format == format); - if ( src.width != dst.width || src.height != dst.height ) + if (src.width != dst.width || src.height != dst.height) { result.Release(); return E_FAIL; } - if ( usewic ) + if (usewic) { - hr = _ConvertUsingWIC( src, pfGUID, targetGUID, filter, threshold, dst ); + hr = ConvertUsingWIC(src, pfGUID, targetGUID, filter, threshold, dst); } else { - hr = _Convert( src, filter, dst, threshold, 0 ); + hr = ConvertCustom(src, filter, dst, threshold, 0); } - if ( FAILED(hr) ) + if (FAILED(hr)) { result.Release(); return hr; @@ -4649,56 +4725,56 @@ HRESULT Convert( const Image* srcImages, size_t nimages, const TexMetadata& meta break; case TEX_DIMENSION_TEXTURE3D: + { + size_t index = 0; + size_t d = metadata.depth; + for (size_t level = 0; level < metadata.mipLevels; ++level) { - size_t index = 0; - size_t d = metadata.depth; - for( size_t level = 0; level < metadata.mipLevels; ++level ) + for (size_t slice = 0; slice < d; ++slice, ++index) { - for( size_t slice = 0; slice < d; ++slice, ++index ) + if (index >= nimages) + return E_FAIL; + + const Image& src = srcImages[index]; + if (src.format != metadata.format) { - if ( index >= nimages ) - return E_FAIL; - - const Image& src = srcImages[ index ]; - if ( src.format != metadata.format ) - { - result.Release(); - return E_FAIL; - } - - if ( (src.width > UINT32_MAX) || (src.height > UINT32_MAX) ) - return E_FAIL; - - const Image& dst = dest[ index ]; - assert( dst.format == format ); - - if ( src.width != dst.width || src.height != dst.height ) - { - result.Release(); - return E_FAIL; - } - - if ( usewic ) - { - hr = _ConvertUsingWIC( src, pfGUID, targetGUID, filter, threshold, dst ); - } - else - { - hr = _Convert( src, filter, dst, threshold, slice ); - } - - if ( FAILED(hr) ) - { - result.Release(); - return hr; - } + result.Release(); + return E_FAIL; } - if ( d > 1 ) - d >>= 1; + if ((src.width > UINT32_MAX) || (src.height > UINT32_MAX)) + return E_FAIL; + + const Image& dst = dest[index]; + assert(dst.format == format); + + if (src.width != dst.width || src.height != dst.height) + { + result.Release(); + return E_FAIL; + } + + if (usewic) + { + hr = ConvertUsingWIC(src, pfGUID, targetGUID, filter, threshold, dst); + } + else + { + hr = ConvertCustom(src, filter, dst, threshold, slice); + } + + if (FAILED(hr)) + { + result.Release(); + return hr; + } } + + if (d > 1) + d >>= 1; } - break; + } + break; default: return E_FAIL; @@ -4712,34 +4788,34 @@ HRESULT Convert( const Image* srcImages, size_t nimages, const TexMetadata& meta // Convert image from planar to single plane (image) //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT ConvertToSinglePlane( const Image& srcImage, ScratchImage& image ) +HRESULT DirectX::ConvertToSinglePlane(const Image& srcImage, ScratchImage& image) { - if ( !IsPlanar(srcImage.format) ) + if (!IsPlanar(srcImage.format)) return E_INVALIDARG; - if ( !srcImage.pixels ) + if (!srcImage.pixels) return E_POINTER; - DXGI_FORMAT format = _PlanarToSingle( srcImage.format ); - if ( format == DXGI_FORMAT_UNKNOWN ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + DXGI_FORMAT format = _PlanarToSingle(srcImage.format); + if (format == DXGI_FORMAT_UNKNOWN) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); - if ( (srcImage.width > UINT32_MAX) || (srcImage.height > UINT32_MAX) ) + if ((srcImage.width > UINT32_MAX) || (srcImage.height > UINT32_MAX)) return E_INVALIDARG; - HRESULT hr = image.Initialize2D( format, srcImage.width, srcImage.height, 1, 1 ); - if ( FAILED(hr) ) + 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 ) + + const Image *rimage = image.GetImage(0, 0, 0); + if (!rimage) { image.Release(); return E_POINTER; } - hr = _ConvertToSinglePlane( srcImage, *rimage ); - if ( FAILED(hr) ) + hr = ConvertToSinglePlane_(srcImage, *rimage); + if (FAILED(hr)) { image.Release(); return hr; @@ -4753,67 +4829,70 @@ HRESULT ConvertToSinglePlane( const Image& srcImage, ScratchImage& image ) // Convert image from planar to single plane (complex) //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT ConvertToSinglePlane( const Image* srcImages, size_t nimages, const TexMetadata& metadata, - ScratchImage& result ) +HRESULT DirectX::ConvertToSinglePlane( + const Image* srcImages, + size_t nimages, + const TexMetadata& metadata, + ScratchImage& result) { - if ( !srcImages || !nimages ) + if (!srcImages || !nimages) return E_INVALIDARG; - if ( metadata.IsVolumemap() ) + if (metadata.IsVolumemap()) { // Direct3D does not support any planar formats for Texture3D - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + 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 ); + DXGI_FORMAT format = _PlanarToSingle(metadata.format); + if (format == DXGI_FORMAT_UNKNOWN) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); - if ( (metadata.width > UINT32_MAX) || (metadata.height > UINT32_MAX) ) + if ((metadata.width > UINT32_MAX) || (metadata.height > UINT32_MAX)) return E_INVALIDARG; TexMetadata mdata2 = metadata; mdata2.format = format; - HRESULT hr = result.Initialize( mdata2 ); - if ( FAILED(hr) ) + HRESULT hr = result.Initialize(mdata2); + if (FAILED(hr)) return hr; - if ( nimages != result.GetImageCount() ) + if (nimages != result.GetImageCount()) { result.Release(); return E_FAIL; } const Image* dest = result.GetImages(); - if ( !dest ) + if (!dest) { result.Release(); return E_POINTER; } - for( size_t index=0; index < nimages; ++index ) + for (size_t index = 0; index < nimages; ++index) { - const Image& src = srcImages[ index ]; - if ( src.format != metadata.format ) + const Image& src = srcImages[index]; + if (src.format != metadata.format) { result.Release(); return E_FAIL; } - if ( (src.width > UINT32_MAX) || (src.height > UINT32_MAX) ) + if ((src.width > UINT32_MAX) || (src.height > UINT32_MAX)) return E_FAIL; - const Image& dst = dest[ index ]; - assert( dst.format == format ); + const Image& dst = dest[index]; + assert(dst.format == format); - if ( src.width != dst.width || src.height != dst.height ) + if (src.width != dst.width || src.height != dst.height) { result.Release(); return E_FAIL; } - hr = _ConvertToSinglePlane( src, dst ); - if ( FAILED(hr) ) + hr = ConvertToSinglePlane_(src, dst); + if (FAILED(hr)) { result.Release(); return hr; @@ -4822,5 +4901,3 @@ HRESULT ConvertToSinglePlane( const Image* srcImages, size_t nimages, const TexM return S_OK; } - -}; // namespace diff --git a/DirectXTex/DirectXTexD3D11.cpp b/DirectXTex/DirectXTexD3D11.cpp index 4cf3f69..5a8d5d4 100644 --- a/DirectXTex/DirectXTexD3D11.cpp +++ b/DirectXTex/DirectXTexD3D11.cpp @@ -23,168 +23,172 @@ #define IID_GRAPHICS_PPV_ARGS(x) IID_PPV_ARGS(x) #endif +using namespace DirectX; using Microsoft::WRL::ComPtr; -namespace DirectX +namespace { - -static HRESULT _Capture( _In_ ID3D11DeviceContext* pContext, _In_ ID3D11Resource* pSource, _In_ const TexMetadata& metadata, - _In_ const ScratchImage& result ) -{ - if ( !pContext || !pSource || !result.GetPixels() ) - return E_POINTER; + HRESULT Capture( + _In_ ID3D11DeviceContext* pContext, + _In_ ID3D11Resource* pSource, + const TexMetadata& metadata, + const ScratchImage& result) + { + if (!pContext || !pSource || !result.GetPixels()) + return E_POINTER; #if defined(_XBOX_ONE) && defined(_TITLE) - ComPtr d3dDevice; - pContext->GetDevice( d3dDevice.GetAddressOf() ); + ComPtr d3dDevice; + pContext->GetDevice(d3dDevice.GetAddressOf()); - if ( d3dDevice->GetCreationFlags() & D3D11_CREATE_DEVICE_IMMEDIATE_CONTEXT_FAST_SEMANTICS ) - { - ComPtr d3dDeviceX; - HRESULT hr = d3dDevice.As( &d3dDeviceX ); - if ( FAILED(hr) ) - return hr; - - ComPtr d3dContextX; - hr = pContext->QueryInterface( IID_GRAPHICS_PPV_ARGS( d3dContextX.GetAddressOf() ) ); - if ( FAILED(hr) ) - return hr; - - UINT64 copyFence = d3dContextX->InsertFence(0); - - while ( d3dDeviceX->IsFencePending( copyFence ) ) + if (d3dDevice->GetCreationFlags() & D3D11_CREATE_DEVICE_IMMEDIATE_CONTEXT_FAST_SEMANTICS) { - SwitchToThread(); + ComPtr d3dDeviceX; + HRESULT hr = d3dDevice.As(&d3dDeviceX); + if (FAILED(hr)) + return hr; + + ComPtr d3dContextX; + hr = pContext->QueryInterface(IID_GRAPHICS_PPV_ARGS(d3dContextX.GetAddressOf())); + if (FAILED(hr)) + return hr; + + UINT64 copyFence = d3dContextX->InsertFence(0); + + while (d3dDeviceX->IsFencePending(copyFence)) + { + SwitchToThread(); + } } - } #endif - if ( metadata.IsVolumemap() ) - { - //--- Volume texture ---------------------------------------------------------- - assert( metadata.arraySize == 1 ); - - size_t height = metadata.height; - size_t depth = metadata.depth; - - for( size_t level = 0; level < metadata.mipLevels; ++level ) + if (metadata.IsVolumemap()) { - UINT dindex = D3D11CalcSubresource( static_cast( level ), 0, static_cast( metadata.mipLevels ) ); + //--- Volume texture ---------------------------------------------------------- + assert(metadata.arraySize == 1); - D3D11_MAPPED_SUBRESOURCE mapped; - HRESULT hr = pContext->Map( pSource, dindex, D3D11_MAP_READ, 0, &mapped ); - if ( FAILED(hr) ) - return hr; - - auto pslice = reinterpret_cast( mapped.pData ); - if ( !pslice ) - { - pContext->Unmap( pSource, dindex ); - return E_POINTER; - } - - size_t lines = ComputeScanlines( metadata.format, height ); - if ( !lines ) - { - pContext->Unmap( pSource, dindex ); - return E_UNEXPECTED; - } - - for( size_t slice = 0; slice < depth; ++slice ) - { - const Image* img = result.GetImage( level, 0, slice ); - if ( !img ) - { - pContext->Unmap( pSource, dindex ); - return E_FAIL; - } - - if ( !img->pixels ) - { - pContext->Unmap( pSource, dindex ); - return E_POINTER; - } - - const uint8_t* sptr = pslice; - uint8_t* dptr = img->pixels; - for( size_t h = 0; h < lines; ++h ) - { - size_t msize = std::min( img->rowPitch, mapped.RowPitch ); - memcpy_s( dptr, img->rowPitch, sptr, msize ); - sptr += mapped.RowPitch; - dptr += img->rowPitch; - } - - pslice += mapped.DepthPitch; - } - - pContext->Unmap( pSource, dindex ); - - if ( height > 1 ) - height >>= 1; - if ( depth > 1 ) - depth >>= 1; - } - } - else - { - //--- 1D or 2D texture -------------------------------------------------------- - assert( metadata.depth == 1 ); - - for( size_t item = 0; item < metadata.arraySize; ++item ) - { size_t height = metadata.height; + size_t depth = metadata.depth; - for( size_t level = 0; level < metadata.mipLevels; ++level ) + for (size_t level = 0; level < metadata.mipLevels; ++level) { - UINT dindex = D3D11CalcSubresource( static_cast( level ), static_cast( item ), static_cast( metadata.mipLevels ) ); + UINT dindex = D3D11CalcSubresource(static_cast(level), 0, static_cast(metadata.mipLevels)); D3D11_MAPPED_SUBRESOURCE mapped; - HRESULT hr = pContext->Map( pSource, dindex, D3D11_MAP_READ, 0, &mapped ); - if ( FAILED(hr) ) + HRESULT hr = pContext->Map(pSource, dindex, D3D11_MAP_READ, 0, &mapped); + if (FAILED(hr)) return hr; - const Image* img = result.GetImage( level, item, 0 ); - if ( !img ) + auto pslice = reinterpret_cast(mapped.pData); + if (!pslice) { - pContext->Unmap( pSource, dindex ); - return E_FAIL; - } - - if ( !img->pixels ) - { - pContext->Unmap( pSource, dindex ); + pContext->Unmap(pSource, dindex); return E_POINTER; } - size_t lines = ComputeScanlines( metadata.format, height ); - if ( !lines ) + size_t lines = ComputeScanlines(metadata.format, height); + if (!lines) { - pContext->Unmap( pSource, dindex ); + pContext->Unmap(pSource, dindex); return E_UNEXPECTED; } - auto sptr = reinterpret_cast( mapped.pData ); - uint8_t* dptr = img->pixels; - for( size_t h = 0; h < lines; ++h ) + for (size_t slice = 0; slice < depth; ++slice) { - size_t msize = std::min( img->rowPitch, mapped.RowPitch ); - memcpy_s( dptr, img->rowPitch, sptr, msize ); - sptr += mapped.RowPitch; - dptr += img->rowPitch; + const Image* img = result.GetImage(level, 0, slice); + if (!img) + { + pContext->Unmap(pSource, dindex); + return E_FAIL; + } + + if (!img->pixels) + { + pContext->Unmap(pSource, dindex); + return E_POINTER; + } + + const uint8_t* sptr = pslice; + uint8_t* dptr = img->pixels; + for (size_t h = 0; h < lines; ++h) + { + size_t msize = std::min(img->rowPitch, mapped.RowPitch); + memcpy_s(dptr, img->rowPitch, sptr, msize); + sptr += mapped.RowPitch; + dptr += img->rowPitch; + } + + pslice += mapped.DepthPitch; } - pContext->Unmap( pSource, dindex ); + pContext->Unmap(pSource, dindex); - if ( height > 1 ) + if (height > 1) height >>= 1; + if (depth > 1) + depth >>= 1; } } - } + else + { + //--- 1D or 2D texture -------------------------------------------------------- + assert(metadata.depth == 1); - return S_OK; + for (size_t item = 0; item < metadata.arraySize; ++item) + { + size_t height = metadata.height; + + for (size_t level = 0; level < metadata.mipLevels; ++level) + { + UINT dindex = D3D11CalcSubresource(static_cast(level), static_cast(item), static_cast(metadata.mipLevels)); + + D3D11_MAPPED_SUBRESOURCE mapped; + HRESULT hr = pContext->Map(pSource, dindex, D3D11_MAP_READ, 0, &mapped); + if (FAILED(hr)) + return hr; + + const Image* img = result.GetImage(level, item, 0); + if (!img) + { + pContext->Unmap(pSource, dindex); + return E_FAIL; + } + + if (!img->pixels) + { + pContext->Unmap(pSource, dindex); + return E_POINTER; + } + + 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; + for (size_t h = 0; h < lines; ++h) + { + size_t msize = std::min(img->rowPitch, mapped.RowPitch); + memcpy_s(dptr, img->rowPitch, sptr, msize); + sptr += mapped.RowPitch; + dptr += img->rowPitch; + } + + pContext->Unmap(pSource, dindex); + + if (height > 1) + height >>= 1; + } + } + } + + return S_OK; + } } @@ -196,9 +200,11 @@ static HRESULT _Capture( _In_ ID3D11DeviceContext* pContext, _In_ ID3D11Resource // Determine if given texture metadata is supported on the given device //------------------------------------------------------------------------------------- _Use_decl_annotations_ -bool IsSupportedTexture( ID3D11Device* pDevice, const TexMetadata& metadata ) +bool DirectX::IsSupportedTexture( + ID3D11Device* pDevice, + const TexMetadata& metadata) { - if ( !pDevice ) + if (!pDevice) return false; D3D_FEATURE_LEVEL fl = pDevice->GetFeatureLevel(); @@ -206,10 +212,10 @@ bool IsSupportedTexture( ID3D11Device* pDevice, const TexMetadata& metadata ) // Validate format DXGI_FORMAT fmt = metadata.format; - if ( !IsValid( fmt ) ) + if (!IsValid(fmt)) return false; - switch( fmt ) + switch (fmt) { case DXGI_FORMAT_BC4_TYPELESS: case DXGI_FORMAT_BC4_UNORM: @@ -217,7 +223,7 @@ bool IsSupportedTexture( ID3D11Device* pDevice, const TexMetadata& metadata ) case DXGI_FORMAT_BC5_TYPELESS: case DXGI_FORMAT_BC5_UNORM: case DXGI_FORMAT_BC5_SNORM: - if ( fl < D3D_FEATURE_LEVEL_10_0 ) + if (fl < D3D_FEATURE_LEVEL_10_0) return false; break; @@ -227,15 +233,15 @@ bool IsSupportedTexture( ID3D11Device* pDevice, const TexMetadata& metadata ) case DXGI_FORMAT_BC7_TYPELESS: case DXGI_FORMAT_BC7_UNORM: case DXGI_FORMAT_BC7_UNORM_SRGB: - if ( fl < D3D_FEATURE_LEVEL_11_0 ) + if (fl < D3D_FEATURE_LEVEL_11_0) return false; break; } // Validate miplevel count - if ( metadata.mipLevels > D3D11_REQ_MIP_LEVELS ) + if (metadata.mipLevels > D3D11_REQ_MIP_LEVELS) return false; - + // Validate array size, dimension, and width/height size_t arraySize = metadata.arraySize; size_t iWidth = metadata.width; @@ -244,100 +250,100 @@ bool IsSupportedTexture( ID3D11Device* pDevice, const TexMetadata& metadata ) // Most cases are known apriori based on feature level, but we use this for robustness to handle the few optional cases UINT formatSupport = 0; - HRESULT hr = pDevice->CheckFormatSupport( fmt, &formatSupport ); - if ( FAILED(hr) ) + HRESULT hr = pDevice->CheckFormatSupport(fmt, &formatSupport); + if (FAILED(hr)) { formatSupport = 0; } - switch ( metadata.dimension ) + switch (metadata.dimension) { case TEX_DIMENSION_TEXTURE1D: - if ( !(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE1D) ) + if (!(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE1D)) return false; - if ( (arraySize > D3D11_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION) - || (iWidth > D3D11_REQ_TEXTURE1D_U_DIMENSION) ) + if ((arraySize > D3D11_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION) + || (iWidth > D3D11_REQ_TEXTURE1D_U_DIMENSION)) return false; - if ( fl < D3D_FEATURE_LEVEL_11_0 ) + if (fl < D3D_FEATURE_LEVEL_11_0) { - if ( (arraySize > D3D10_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION) - || (iWidth > D3D10_REQ_TEXTURE1D_U_DIMENSION) ) + if ((arraySize > D3D10_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION) + || (iWidth > D3D10_REQ_TEXTURE1D_U_DIMENSION)) return false; - if ( fl < D3D_FEATURE_LEVEL_10_0 ) + if (fl < D3D_FEATURE_LEVEL_10_0) { - if ( (arraySize > 1) || (iWidth > D3D_FL9_3_REQ_TEXTURE1D_U_DIMENSION) ) + if ((arraySize > 1) || (iWidth > D3D_FL9_3_REQ_TEXTURE1D_U_DIMENSION)) return false; - if ( (fl < D3D_FEATURE_LEVEL_9_3) && (iWidth > D3D_FL9_1_REQ_TEXTURE1D_U_DIMENSION ) ) + if ((fl < D3D_FEATURE_LEVEL_9_3) && (iWidth > D3D_FL9_1_REQ_TEXTURE1D_U_DIMENSION)) return false; } } break; case TEX_DIMENSION_TEXTURE2D: - if ( metadata.IsCubemap() ) + if (metadata.IsCubemap()) { - if ( !(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURECUBE) ) + if (!(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURECUBE)) return false; - if ( (arraySize > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) - || (iWidth > D3D11_REQ_TEXTURECUBE_DIMENSION) - || (iHeight > D3D11_REQ_TEXTURECUBE_DIMENSION)) + if ((arraySize > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) + || (iWidth > D3D11_REQ_TEXTURECUBE_DIMENSION) + || (iHeight > D3D11_REQ_TEXTURECUBE_DIMENSION)) return false; - if ( fl < D3D_FEATURE_LEVEL_11_0 ) + if (fl < D3D_FEATURE_LEVEL_11_0) { - if ( (arraySize > D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) - || (iWidth > D3D10_REQ_TEXTURECUBE_DIMENSION) - || (iHeight > D3D10_REQ_TEXTURECUBE_DIMENSION)) + if ((arraySize > D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) + || (iWidth > D3D10_REQ_TEXTURECUBE_DIMENSION) + || (iHeight > D3D10_REQ_TEXTURECUBE_DIMENSION)) return false; - if ( (fl < D3D_FEATURE_LEVEL_10_1) && (arraySize != 6) ) + if ((fl < D3D_FEATURE_LEVEL_10_1) && (arraySize != 6)) return false; - if ( fl < D3D_FEATURE_LEVEL_10_0 ) + if (fl < D3D_FEATURE_LEVEL_10_0) { - if ( (iWidth > D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION ) - || (iHeight > D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION ) ) + if ((iWidth > D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION) + || (iHeight > D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION)) return false; - if ( (fl < D3D_FEATURE_LEVEL_9_3) - && ( (iWidth > D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION) - || (iHeight > D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION) ) ) + if ((fl < D3D_FEATURE_LEVEL_9_3) + && ((iWidth > D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION) + || (iHeight > D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION))) return false; } } } else // Not a cube map { - if ( !(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) ) + if (!(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D)) return false; - if ( (arraySize > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) - || (iWidth > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION) - || (iHeight > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION)) + if ((arraySize > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) + || (iWidth > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION) + || (iHeight > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION)) return false; - if ( fl < D3D_FEATURE_LEVEL_11_0 ) + if (fl < D3D_FEATURE_LEVEL_11_0) { - if ( (arraySize > D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) - || (iWidth > D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION) - || (iHeight > D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION)) + if ((arraySize > D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) + || (iWidth > D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION) + || (iHeight > D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION)) return false; - if ( fl < D3D_FEATURE_LEVEL_10_0 ) + if (fl < D3D_FEATURE_LEVEL_10_0) { - if ( (arraySize > 1) - || (iWidth > D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION) - || (iHeight > D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION) ) + if ((arraySize > 1) + || (iWidth > D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION) + || (iHeight > D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION)) return false; - if ( (fl < D3D_FEATURE_LEVEL_9_3) - && ( (iWidth > D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION) - || (iHeight > D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION) ) ) + if ((fl < D3D_FEATURE_LEVEL_9_3) + && ((iWidth > D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION) + || (iHeight > D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION))) return false; } } @@ -345,27 +351,27 @@ bool IsSupportedTexture( ID3D11Device* pDevice, const TexMetadata& metadata ) break; case TEX_DIMENSION_TEXTURE3D: - if ( !(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE3D) ) + if (!(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE3D)) return false; - if ( (arraySize > 1) - || (iWidth > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) - || (iHeight > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) - || (iDepth > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ) + if ((arraySize > 1) + || (iWidth > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) + || (iHeight > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) + || (iDepth > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION)) return false; - if ( fl < D3D_FEATURE_LEVEL_11_0 ) + if (fl < D3D_FEATURE_LEVEL_11_0) { - if ( (iWidth > D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) - || (iHeight > D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) - || (iDepth > D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ) + if ((iWidth > D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) + || (iHeight > D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) + || (iDepth > D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION)) return false; - if ( fl < D3D_FEATURE_LEVEL_10_0 ) + if (fl < D3D_FEATURE_LEVEL_10_0) { - if ( (iWidth > D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) - || (iHeight > D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) - || (iDepth > D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ) + if ((iWidth > D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) + || (iHeight > D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) + || (iDepth > D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION)) return false; } } @@ -384,98 +390,111 @@ bool IsSupportedTexture( ID3D11Device* pDevice, const TexMetadata& metadata ) // Create a texture resource //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT CreateTexture( ID3D11Device* pDevice, const Image* srcImages, size_t nimages, const TexMetadata& metadata, - ID3D11Resource** ppResource ) +HRESULT DirectX::CreateTexture( + ID3D11Device* pDevice, + const Image* srcImages, + size_t nimages, + const TexMetadata& metadata, + ID3D11Resource** ppResource) { - return CreateTextureEx( pDevice, srcImages, nimages, metadata, - D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0, false, - ppResource ); + return CreateTextureEx( + pDevice, srcImages, nimages, metadata, + D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0, false, + ppResource); } _Use_decl_annotations_ -HRESULT CreateTextureEx( ID3D11Device* pDevice, const Image* srcImages, size_t nimages, const TexMetadata& metadata, - D3D11_USAGE usage, unsigned int bindFlags, unsigned int cpuAccessFlags, unsigned int miscFlags, bool forceSRGB, - ID3D11Resource** ppResource ) +HRESULT DirectX::CreateTextureEx( + ID3D11Device* pDevice, + const Image* srcImages, + size_t nimages, + const TexMetadata& metadata, + D3D11_USAGE usage, + unsigned int bindFlags, + unsigned int cpuAccessFlags, + unsigned int miscFlags, + bool forceSRGB, + ID3D11Resource** ppResource) { - if ( !pDevice || !srcImages || !nimages || !ppResource ) + if (!pDevice || !srcImages || !nimages || !ppResource) return E_INVALIDARG; *ppResource = nullptr; - if ( !metadata.mipLevels || !metadata.arraySize ) + if (!metadata.mipLevels || !metadata.arraySize) return E_INVALIDARG; - if ( (metadata.width > UINT32_MAX) || (metadata.height > UINT32_MAX) - || (metadata.mipLevels > UINT32_MAX) || (metadata.arraySize > UINT32_MAX) ) + if ((metadata.width > UINT32_MAX) || (metadata.height > UINT32_MAX) + || (metadata.mipLevels > UINT32_MAX) || (metadata.arraySize > UINT32_MAX)) return E_INVALIDARG; - std::unique_ptr initData( new (std::nothrow) D3D11_SUBRESOURCE_DATA[ metadata.mipLevels * metadata.arraySize ] ); - if ( !initData ) + std::unique_ptr initData(new (std::nothrow) D3D11_SUBRESOURCE_DATA[metadata.mipLevels * metadata.arraySize]); + if (!initData) return E_OUTOFMEMORY; // Fill out subresource array - if ( metadata.IsVolumemap() ) + if (metadata.IsVolumemap()) { //--- Volume case ------------------------------------------------------------- - if ( !metadata.depth ) + if (!metadata.depth) return E_INVALIDARG; - if ( metadata.depth > UINT32_MAX ) + if (metadata.depth > UINT32_MAX) return E_INVALIDARG; - if ( metadata.arraySize > 1 ) + if (metadata.arraySize > 1) // Direct3D 11 doesn't support arrays of 3D textures - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); size_t depth = metadata.depth; size_t idx = 0; - for( size_t level = 0; level < metadata.mipLevels; ++level ) + for (size_t level = 0; level < metadata.mipLevels; ++level) { - size_t index = metadata.ComputeIndex( level, 0, 0 ); - if ( index >= nimages ) + size_t index = metadata.ComputeIndex(level, 0, 0); + if (index >= nimages) return E_FAIL; - const Image& img = srcImages[ index ]; + const Image& img = srcImages[index]; - if ( img.format != metadata.format ) + if (img.format != metadata.format) return E_FAIL; - if ( !img.pixels ) + if (!img.pixels) return E_POINTER; // Verify pixels in image 1 .. (depth-1) are exactly image->slicePitch apart // For 3D textures, this relies on all slices of the same miplevel being continous in memory // (this is how ScratchImage lays them out), which is why we just give the 0th slice to Direct3D 11 const uint8_t* pSlice = img.pixels + img.slicePitch; - for( size_t slice = 1; slice < depth; ++slice ) + for (size_t slice = 1; slice < depth; ++slice) { - size_t tindex = metadata.ComputeIndex( level, 0, slice ); - if ( tindex >= nimages ) + size_t tindex = metadata.ComputeIndex(level, 0, slice); + if (tindex >= nimages) return E_FAIL; - const Image& timg = srcImages[ tindex ]; + const Image& timg = srcImages[tindex]; - if ( !timg.pixels ) + if (!timg.pixels) return E_POINTER; - if ( timg.pixels != pSlice - || timg.format != metadata.format - || timg.rowPitch != img.rowPitch - || timg.slicePitch != img.slicePitch ) + if (timg.pixels != pSlice + || timg.format != metadata.format + || timg.rowPitch != img.rowPitch + || timg.slicePitch != img.slicePitch) return E_FAIL; pSlice = timg.pixels + img.slicePitch; } - assert( idx < (metadata.mipLevels * metadata.arraySize) ); + assert(idx < (metadata.mipLevels * metadata.arraySize)); initData[idx].pSysMem = img.pixels; - initData[idx].SysMemPitch = static_cast( img.rowPitch ); - initData[idx].SysMemSlicePitch = static_cast( img.slicePitch ); + initData[idx].SysMemPitch = static_cast(img.rowPitch); + initData[idx].SysMemSlicePitch = static_cast(img.slicePitch); ++idx; - if ( depth > 1 ) + if (depth > 1) depth >>= 1; } } @@ -483,27 +502,27 @@ HRESULT CreateTextureEx( ID3D11Device* pDevice, const Image* srcImages, size_t n { //--- 1D or 2D texture case --------------------------------------------------- size_t idx = 0; - for( size_t item = 0; item < metadata.arraySize; ++item ) + for (size_t item = 0; item < metadata.arraySize; ++item) { - for( size_t level = 0; level < metadata.mipLevels; ++level ) + for (size_t level = 0; level < metadata.mipLevels; ++level) { - size_t index = metadata.ComputeIndex( level, item, 0 ); - if ( index >= nimages ) + size_t index = metadata.ComputeIndex(level, item, 0); + if (index >= nimages) return E_FAIL; - const Image& img = srcImages[ index ]; + const Image& img = srcImages[index]; - if ( img.format != metadata.format ) + if (img.format != metadata.format) return E_FAIL; - if ( !img.pixels ) + if (!img.pixels) return E_POINTER; - assert( idx < (metadata.mipLevels * metadata.arraySize) ); + assert(idx < (metadata.mipLevels * metadata.arraySize)); initData[idx].pSysMem = img.pixels; - initData[idx].SysMemPitch = static_cast( img.rowPitch ); - initData[idx].SysMemSlicePitch = static_cast( img.slicePitch ); + initData[idx].SysMemPitch = static_cast(img.rowPitch); + initData[idx].SysMemSlicePitch = static_cast(img.slicePitch); ++idx; } } @@ -512,64 +531,64 @@ HRESULT CreateTextureEx( ID3D11Device* pDevice, const Image* srcImages, size_t n // Create texture using static initialization data HRESULT hr = E_FAIL; - DXGI_FORMAT tformat = ( forceSRGB ) ? MakeSRGB( metadata.format ) : metadata.format; + DXGI_FORMAT tformat = (forceSRGB) ? MakeSRGB(metadata.format) : metadata.format; - switch ( metadata.dimension ) + switch (metadata.dimension) { case TEX_DIMENSION_TEXTURE1D: - { - D3D11_TEXTURE1D_DESC desc; - desc.Width = static_cast( metadata.width ); - desc.MipLevels = static_cast( metadata.mipLevels ); - desc.ArraySize = static_cast( metadata.arraySize ); - desc.Format = tformat; - desc.Usage = usage; - desc.BindFlags = bindFlags; - desc.CPUAccessFlags = cpuAccessFlags; - desc.MiscFlags = miscFlags & ~D3D11_RESOURCE_MISC_TEXTURECUBE; + { + D3D11_TEXTURE1D_DESC desc; + desc.Width = static_cast(metadata.width); + desc.MipLevels = static_cast(metadata.mipLevels); + desc.ArraySize = static_cast(metadata.arraySize); + desc.Format = tformat; + desc.Usage = usage; + desc.BindFlags = bindFlags; + desc.CPUAccessFlags = cpuAccessFlags; + desc.MiscFlags = miscFlags & ~D3D11_RESOURCE_MISC_TEXTURECUBE; - hr = pDevice->CreateTexture1D( &desc, initData.get(), reinterpret_cast(ppResource) ); - } - break; + hr = pDevice->CreateTexture1D(&desc, initData.get(), reinterpret_cast(ppResource)); + } + break; case TEX_DIMENSION_TEXTURE2D: - { - D3D11_TEXTURE2D_DESC desc; - desc.Width = static_cast( metadata.width ); - desc.Height = static_cast( metadata.height ); - desc.MipLevels = static_cast( metadata.mipLevels ); - desc.ArraySize = static_cast( metadata.arraySize ); - desc.Format = tformat; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = usage; - desc.BindFlags = bindFlags; - desc.CPUAccessFlags = cpuAccessFlags; - if ( metadata.IsCubemap() ) - desc.MiscFlags = miscFlags | D3D11_RESOURCE_MISC_TEXTURECUBE; - else - desc.MiscFlags = miscFlags & ~D3D11_RESOURCE_MISC_TEXTURECUBE; - - hr = pDevice->CreateTexture2D( &desc, initData.get(), reinterpret_cast(ppResource) ); - } - break; - - case TEX_DIMENSION_TEXTURE3D: - { - D3D11_TEXTURE3D_DESC desc; - desc.Width = static_cast( metadata.width ); - desc.Height = static_cast( metadata.height ); - desc.Depth = static_cast( metadata.depth ); - desc.MipLevels = static_cast( metadata.mipLevels ); - desc.Format = tformat; - desc.Usage = usage; - desc.BindFlags = bindFlags; - desc.CPUAccessFlags = cpuAccessFlags; + { + D3D11_TEXTURE2D_DESC desc; + desc.Width = static_cast(metadata.width); + desc.Height = static_cast(metadata.height); + desc.MipLevels = static_cast(metadata.mipLevels); + desc.ArraySize = static_cast(metadata.arraySize); + desc.Format = tformat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = usage; + desc.BindFlags = bindFlags; + desc.CPUAccessFlags = cpuAccessFlags; + if (metadata.IsCubemap()) + desc.MiscFlags = miscFlags | D3D11_RESOURCE_MISC_TEXTURECUBE; + else desc.MiscFlags = miscFlags & ~D3D11_RESOURCE_MISC_TEXTURECUBE; - hr = pDevice->CreateTexture3D( &desc, initData.get(), reinterpret_cast(ppResource) ); - } - break; + hr = pDevice->CreateTexture2D(&desc, initData.get(), reinterpret_cast(ppResource)); + } + break; + + case TEX_DIMENSION_TEXTURE3D: + { + D3D11_TEXTURE3D_DESC desc; + desc.Width = static_cast(metadata.width); + desc.Height = static_cast(metadata.height); + desc.Depth = static_cast(metadata.depth); + desc.MipLevels = static_cast(metadata.mipLevels); + desc.Format = tformat; + desc.Usage = usage; + desc.BindFlags = bindFlags; + desc.CPUAccessFlags = cpuAccessFlags; + desc.MiscFlags = miscFlags & ~D3D11_RESOURCE_MISC_TEXTURECUBE; + + hr = pDevice->CreateTexture3D(&desc, initData.get(), reinterpret_cast(ppResource)); + } + break; } return hr; @@ -580,99 +599,112 @@ HRESULT CreateTextureEx( ID3D11Device* pDevice, const Image* srcImages, size_t n // Create a shader resource view and associated texture //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT CreateShaderResourceView( ID3D11Device* pDevice, const Image* srcImages, size_t nimages, const TexMetadata& metadata, - ID3D11ShaderResourceView** ppSRV ) +HRESULT DirectX::CreateShaderResourceView( + ID3D11Device* pDevice, + const Image* srcImages, + size_t nimages, + const TexMetadata& metadata, + ID3D11ShaderResourceView** ppSRV) { - return CreateShaderResourceViewEx( pDevice, srcImages, nimages, metadata, - D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0, false, - ppSRV ); + return CreateShaderResourceViewEx( + pDevice, srcImages, nimages, metadata, + D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0, false, + ppSRV); } _Use_decl_annotations_ -HRESULT CreateShaderResourceViewEx( ID3D11Device* pDevice, const Image* srcImages, size_t nimages, const TexMetadata& metadata, - D3D11_USAGE usage, unsigned int bindFlags, unsigned int cpuAccessFlags, unsigned int miscFlags, bool forceSRGB, - ID3D11ShaderResourceView** ppSRV ) +HRESULT DirectX::CreateShaderResourceViewEx( + ID3D11Device* pDevice, + const Image* srcImages, + size_t nimages, + const TexMetadata& metadata, + D3D11_USAGE usage, + unsigned int bindFlags, + unsigned int cpuAccessFlags, + unsigned int miscFlags, + bool forceSRGB, + ID3D11ShaderResourceView** ppSRV) { - if ( !ppSRV ) + if (!ppSRV) return E_INVALIDARG; *ppSRV = nullptr; ComPtr resource; - HRESULT hr = CreateTextureEx( pDevice, srcImages, nimages, metadata, - usage, bindFlags, cpuAccessFlags, miscFlags, forceSRGB, - resource.GetAddressOf() ); - if ( FAILED(hr) ) + HRESULT hr = CreateTextureEx(pDevice, srcImages, nimages, metadata, + usage, bindFlags, cpuAccessFlags, miscFlags, forceSRGB, + resource.GetAddressOf()); + if (FAILED(hr)) return hr; - assert( resource ); + assert(resource); D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc = {}; - if ( forceSRGB ) - SRVDesc.Format = MakeSRGB( metadata.format ); + if (forceSRGB) + SRVDesc.Format = MakeSRGB(metadata.format); else SRVDesc.Format = metadata.format; - switch ( metadata.dimension ) + switch (metadata.dimension) { case TEX_DIMENSION_TEXTURE1D: - if ( metadata.arraySize > 1 ) + if (metadata.arraySize > 1) { SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE1DARRAY; - SRVDesc.Texture1DArray.MipLevels = static_cast( metadata.mipLevels ); - SRVDesc.Texture1DArray.ArraySize = static_cast( metadata.arraySize ); + SRVDesc.Texture1DArray.MipLevels = static_cast(metadata.mipLevels); + SRVDesc.Texture1DArray.ArraySize = static_cast(metadata.arraySize); } else { SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE1D; - SRVDesc.Texture1D.MipLevels = static_cast( metadata.mipLevels ); + SRVDesc.Texture1D.MipLevels = static_cast(metadata.mipLevels); } break; case TEX_DIMENSION_TEXTURE2D: - if ( metadata.IsCubemap() ) + if (metadata.IsCubemap()) { if (metadata.arraySize > 6) { - assert( (metadata.arraySize % 6) == 0 ); + assert((metadata.arraySize % 6) == 0); SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURECUBEARRAY; - SRVDesc.TextureCubeArray.MipLevels = static_cast( metadata.mipLevels ); - SRVDesc.TextureCubeArray.NumCubes = static_cast( metadata.arraySize / 6 ); + SRVDesc.TextureCubeArray.MipLevels = static_cast(metadata.mipLevels); + SRVDesc.TextureCubeArray.NumCubes = static_cast(metadata.arraySize / 6); } else { SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURECUBE; - SRVDesc.TextureCube.MipLevels = static_cast( metadata.mipLevels ); + SRVDesc.TextureCube.MipLevels = static_cast(metadata.mipLevels); } } - else if ( metadata.arraySize > 1 ) + else if (metadata.arraySize > 1) { SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2DARRAY; - SRVDesc.Texture2DArray.MipLevels = static_cast( metadata.mipLevels ); - SRVDesc.Texture2DArray.ArraySize = static_cast( metadata.arraySize ); + SRVDesc.Texture2DArray.MipLevels = static_cast(metadata.mipLevels); + SRVDesc.Texture2DArray.ArraySize = static_cast(metadata.arraySize); } else { SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2D; - SRVDesc.Texture2D.MipLevels = static_cast( metadata.mipLevels ); + SRVDesc.Texture2D.MipLevels = static_cast(metadata.mipLevels); } break; case TEX_DIMENSION_TEXTURE3D: - assert( metadata.arraySize == 1 ); + assert(metadata.arraySize == 1); SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE3D; - SRVDesc.Texture3D.MipLevels = static_cast( metadata.mipLevels ); + SRVDesc.Texture3D.MipLevels = static_cast(metadata.mipLevels); break; default: return E_FAIL; } - hr = pDevice->CreateShaderResourceView( resource.Get(), &SRVDesc, ppSRV ); - if ( FAILED(hr) ) + hr = pDevice->CreateShaderResourceView(resource.Get(), &SRVDesc, ppSRV); + if (FAILED(hr)) return hr; - assert( *ppSRV ); + assert(*ppSRV); return S_OK; } @@ -682,214 +714,218 @@ HRESULT CreateShaderResourceViewEx( ID3D11Device* pDevice, const Image* srcImage // Save a texture resource to a DDS file in memory/on disk //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT CaptureTexture( ID3D11Device* pDevice, ID3D11DeviceContext* pContext, ID3D11Resource* pSource, ScratchImage& result ) +HRESULT DirectX::CaptureTexture( + ID3D11Device* pDevice, + ID3D11DeviceContext* pContext, + ID3D11Resource* pSource, + ScratchImage& result) { - if ( !pDevice || !pContext || !pSource ) + if (!pDevice || !pContext || !pSource) return E_INVALIDARG; D3D11_RESOURCE_DIMENSION resType = D3D11_RESOURCE_DIMENSION_UNKNOWN; - pSource->GetType( &resType ); + pSource->GetType(&resType); HRESULT hr; - switch( resType ) + switch (resType) { case D3D11_RESOURCE_DIMENSION_TEXTURE1D: - { - ComPtr pTexture; - hr = pSource->QueryInterface( IID_GRAPHICS_PPV_ARGS( pTexture.GetAddressOf() ) ); - if ( FAILED(hr) ) - break; + { + ComPtr pTexture; + hr = pSource->QueryInterface(IID_GRAPHICS_PPV_ARGS(pTexture.GetAddressOf())); + if (FAILED(hr)) + break; - assert( pTexture ); + assert(pTexture); - D3D11_TEXTURE1D_DESC desc; - pTexture->GetDesc( &desc ); + D3D11_TEXTURE1D_DESC desc; + pTexture->GetDesc(&desc); - desc.BindFlags = 0; - desc.MiscFlags = 0; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.MiscFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.Usage = D3D11_USAGE_STAGING; - ComPtr pStaging; - hr = pDevice->CreateTexture1D( &desc, 0, pStaging.GetAddressOf() ); - if ( FAILED(hr) ) - break; + ComPtr pStaging; + hr = pDevice->CreateTexture1D(&desc, 0, pStaging.GetAddressOf()); + if (FAILED(hr)) + break; - assert( pStaging ); + assert(pStaging); - pContext->CopyResource( pStaging.Get(), pSource ); + pContext->CopyResource(pStaging.Get(), pSource); - TexMetadata mdata; - mdata.width = desc.Width; - mdata.height = mdata.depth = 1; - mdata.arraySize = desc.ArraySize; - mdata.mipLevels = desc.MipLevels; - mdata.miscFlags = 0; - mdata.miscFlags2 = 0; - mdata.format = desc.Format; - mdata.dimension = TEX_DIMENSION_TEXTURE1D; + TexMetadata mdata; + mdata.width = desc.Width; + mdata.height = mdata.depth = 1; + mdata.arraySize = desc.ArraySize; + mdata.mipLevels = desc.MipLevels; + mdata.miscFlags = 0; + mdata.miscFlags2 = 0; + mdata.format = desc.Format; + mdata.dimension = TEX_DIMENSION_TEXTURE1D; - hr = result.Initialize( mdata ); - if ( FAILED(hr) ) - break; + hr = result.Initialize(mdata); + if (FAILED(hr)) + break; - hr = _Capture( pContext, pStaging.Get(), mdata, result ); - } - break; + hr = Capture(pContext, pStaging.Get(), mdata, result); + } + break; case D3D11_RESOURCE_DIMENSION_TEXTURE2D: + { + ComPtr pTexture; + hr = pSource->QueryInterface(IID_GRAPHICS_PPV_ARGS(pTexture.GetAddressOf())); + if (FAILED(hr)) + break; + + assert(pTexture); + + D3D11_TEXTURE2D_DESC desc; + pTexture->GetDesc(&desc); + + ComPtr pStaging; + if (desc.SampleDesc.Count > 1) { - ComPtr pTexture; - hr = pSource->QueryInterface( IID_GRAPHICS_PPV_ARGS( pTexture.GetAddressOf() ) ); - if ( FAILED(hr) ) + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + + ComPtr pTemp; + hr = pDevice->CreateTexture2D(&desc, 0, pTemp.GetAddressOf()); + if (FAILED(hr)) break; - assert( pTexture ); + assert(pTemp); - D3D11_TEXTURE2D_DESC desc; - pTexture->GetDesc( &desc ); - - ComPtr pStaging; - if ( desc.SampleDesc.Count > 1 ) + DXGI_FORMAT fmt = desc.Format; + if (IsTypeless(fmt)) { - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - - ComPtr pTemp; - hr = pDevice->CreateTexture2D( &desc, 0, pTemp.GetAddressOf() ); - if ( FAILED(hr) ) - break; - - assert( pTemp ); - - DXGI_FORMAT fmt = desc.Format; - if ( IsTypeless(fmt) ) - { - // Assume a UNORM if it exists otherwise use FLOAT - fmt = MakeTypelessUNORM( fmt ); - fmt = MakeTypelessFLOAT( fmt ); - } - - UINT support = 0; - hr = pDevice->CheckFormatSupport( fmt, &support ); - if ( FAILED(hr) ) - break; - - if ( !(support & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE) ) - { - hr = E_FAIL; - break; - } - - for( UINT item = 0; item < desc.ArraySize; ++item ) - { - for( UINT level = 0; level < desc.MipLevels; ++level ) - { - UINT index = D3D11CalcSubresource( level, item, desc.MipLevels ); - pContext->ResolveSubresource( pTemp.Get(), index, pSource, index, fmt ); - } - } - - desc.BindFlags = 0; - desc.MiscFlags &= D3D11_RESOURCE_MISC_TEXTURECUBE; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - desc.Usage = D3D11_USAGE_STAGING; - - hr = pDevice->CreateTexture2D( &desc, 0, pStaging.GetAddressOf() ); - if ( FAILED(hr) ) - break; - - assert( pStaging ); - - pContext->CopyResource( pStaging.Get(), pTemp.Get() ); - } - else - { - desc.BindFlags = 0; - desc.MiscFlags &= D3D11_RESOURCE_MISC_TEXTURECUBE; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - desc.Usage = D3D11_USAGE_STAGING; - - hr = pDevice->CreateTexture2D( &desc, 0, &pStaging ); - if ( FAILED(hr) ) - break; - - assert( pStaging ); - - pContext->CopyResource( pStaging.Get(), pSource ); + // Assume a UNORM if it exists otherwise use FLOAT + fmt = MakeTypelessUNORM(fmt); + fmt = MakeTypelessFLOAT(fmt); } - TexMetadata mdata; - mdata.width = desc.Width; - mdata.height = desc.Height; - mdata.depth = 1; - mdata.arraySize = desc.ArraySize; - mdata.mipLevels = desc.MipLevels; - mdata.miscFlags = (desc.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) ? TEX_MISC_TEXTURECUBE : 0; - mdata.miscFlags2 = 0; - mdata.format = desc.Format; - mdata.dimension = TEX_DIMENSION_TEXTURE2D; - - hr = result.Initialize( mdata ); - if ( FAILED(hr) ) + UINT support = 0; + hr = pDevice->CheckFormatSupport(fmt, &support); + if (FAILED(hr)) break; - hr = _Capture( pContext, pStaging.Get(), mdata, result ); - } - break; - - case D3D11_RESOURCE_DIMENSION_TEXTURE3D: - { - ComPtr pTexture; - hr = pSource->QueryInterface( IID_GRAPHICS_PPV_ARGS( pTexture.GetAddressOf() ) ); - if ( FAILED(hr) ) + if (!(support & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE)) + { + hr = E_FAIL; break; + } - assert( pTexture ); - - D3D11_TEXTURE3D_DESC desc; - pTexture->GetDesc( &desc ); + for (UINT item = 0; item < desc.ArraySize; ++item) + { + for (UINT level = 0; level < desc.MipLevels; ++level) + { + UINT index = D3D11CalcSubresource(level, item, desc.MipLevels); + pContext->ResolveSubresource(pTemp.Get(), index, pSource, index, fmt); + } + } desc.BindFlags = 0; - desc.MiscFlags = 0; + desc.MiscFlags &= D3D11_RESOURCE_MISC_TEXTURECUBE; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.Usage = D3D11_USAGE_STAGING; - ComPtr pStaging; - hr = pDevice->CreateTexture3D( &desc, 0, pStaging.GetAddressOf() ); - if ( FAILED(hr) ) + hr = pDevice->CreateTexture2D(&desc, 0, pStaging.GetAddressOf()); + if (FAILED(hr)) break; - assert( pStaging ); + assert(pStaging); - pContext->CopyResource( pStaging.Get(), pSource ); - - TexMetadata mdata; - mdata.width = desc.Width; - mdata.height = desc.Height; - mdata.depth = desc.Depth; - mdata.arraySize = 1; - mdata.mipLevels = desc.MipLevels; - mdata.miscFlags = 0; - mdata.miscFlags2 = 0; - mdata.format = desc.Format; - mdata.dimension = TEX_DIMENSION_TEXTURE3D; - - hr = result.Initialize( mdata ); - if ( FAILED(hr) ) - break; - - hr = _Capture( pContext, pStaging.Get(), mdata, result ); + pContext->CopyResource(pStaging.Get(), pTemp.Get()); } - break; + else + { + desc.BindFlags = 0; + desc.MiscFlags &= D3D11_RESOURCE_MISC_TEXTURECUBE; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.Usage = D3D11_USAGE_STAGING; + + hr = pDevice->CreateTexture2D(&desc, 0, &pStaging); + if (FAILED(hr)) + break; + + assert(pStaging); + + pContext->CopyResource(pStaging.Get(), pSource); + } + + TexMetadata mdata; + mdata.width = desc.Width; + mdata.height = desc.Height; + mdata.depth = 1; + mdata.arraySize = desc.ArraySize; + mdata.mipLevels = desc.MipLevels; + mdata.miscFlags = (desc.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) ? TEX_MISC_TEXTURECUBE : 0; + mdata.miscFlags2 = 0; + mdata.format = desc.Format; + mdata.dimension = TEX_DIMENSION_TEXTURE2D; + + hr = result.Initialize(mdata); + if (FAILED(hr)) + break; + + hr = Capture(pContext, pStaging.Get(), mdata, result); + } + break; + + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: + { + ComPtr pTexture; + hr = pSource->QueryInterface(IID_GRAPHICS_PPV_ARGS(pTexture.GetAddressOf())); + if (FAILED(hr)) + break; + + assert(pTexture); + + D3D11_TEXTURE3D_DESC desc; + pTexture->GetDesc(&desc); + + desc.BindFlags = 0; + desc.MiscFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.Usage = D3D11_USAGE_STAGING; + + ComPtr pStaging; + hr = pDevice->CreateTexture3D(&desc, 0, pStaging.GetAddressOf()); + if (FAILED(hr)) + break; + + assert(pStaging); + + pContext->CopyResource(pStaging.Get(), pSource); + + TexMetadata mdata; + mdata.width = desc.Width; + mdata.height = desc.Height; + mdata.depth = desc.Depth; + mdata.arraySize = 1; + mdata.mipLevels = desc.MipLevels; + mdata.miscFlags = 0; + mdata.miscFlags2 = 0; + mdata.format = desc.Format; + mdata.dimension = TEX_DIMENSION_TEXTURE3D; + + hr = result.Initialize(mdata); + if (FAILED(hr)) + break; + + hr = Capture(pContext, pStaging.Get(), mdata, result); + } + break; default: hr = E_FAIL; break; } - if ( FAILED(hr) ) + if (FAILED(hr)) { result.Release(); return hr; @@ -897,5 +933,3 @@ HRESULT CaptureTexture( ID3D11Device* pDevice, ID3D11DeviceContext* pContext, ID return S_OK; } - -}; // namespace diff --git a/DirectXTex/DirectXTexDDS.cpp b/DirectXTex/DirectXTexDDS.cpp index fb2cc9a..24b736f 100644 --- a/DirectXTex/DirectXTexDDS.cpp +++ b/DirectXTex/DirectXTexDDS.cpp @@ -17,6 +17,8 @@ #include "dds.h" +using namespace DirectX; + namespace { class auto_delete_file @@ -31,7 +33,7 @@ namespace { if (m_handle) { - FILE_DISPOSITION_INFO info = {0}; + FILE_DISPOSITION_INFO info = { 0 }; info.DeleteFile = TRUE; (void)SetFileInformationByHandle(m_handle, FileDispositionInfo, &info, sizeof(info)); } @@ -42,426 +44,427 @@ namespace private: HANDLE m_handle; }; -} -namespace DirectX -{ - -//------------------------------------------------------------------------------------- -// Legacy format mapping table (used for DDS files without 'DX10' extended header) -//------------------------------------------------------------------------------------- -enum CONVERSION_FLAGS -{ - CONV_FLAGS_NONE = 0x0, - CONV_FLAGS_EXPAND = 0x1, // Conversion requires expanded pixel size - CONV_FLAGS_NOALPHA = 0x2, // Conversion requires setting alpha to known value - CONV_FLAGS_SWIZZLE = 0x4, // BGR/RGB order swizzling required - CONV_FLAGS_PAL8 = 0x8, // Has an 8-bit palette - CONV_FLAGS_888 = 0x10, // Source is an 8:8:8 (24bpp) format - CONV_FLAGS_565 = 0x20, // Source is a 5:6:5 (16bpp) format - CONV_FLAGS_5551 = 0x40, // Source is a 5:5:5:1 (16bpp) format - CONV_FLAGS_4444 = 0x80, // Source is a 4:4:4:4 (16bpp) format - CONV_FLAGS_44 = 0x100, // Source is a 4:4 (8bpp) format - CONV_FLAGS_332 = 0x200, // Source is a 3:3:2 (8bpp) format - CONV_FLAGS_8332 = 0x400, // Source is a 8:3:3:2 (16bpp) format - CONV_FLAGS_A8P8 = 0x800, // Has an 8-bit palette with an alpha channel - CONV_FLAGS_DX10 = 0x10000, // Has the 'DX10' extension header - CONV_FLAGS_PMALPHA = 0x20000, // Contains premultiplied alpha data - CONV_FLAGS_L8 = 0x40000, // Source is a 8 luminance format - CONV_FLAGS_L16 = 0x80000, // Source is a 16 luminance format - CONV_FLAGS_A8L8 = 0x100000, // Source is a 8:8 luminance format -}; - -struct LegacyDDS -{ - DXGI_FORMAT format; - DWORD convFlags; - DDS_PIXELFORMAT ddpf; -}; - -const LegacyDDS g_LegacyDDSMap[] = -{ - { DXGI_FORMAT_BC1_UNORM, CONV_FLAGS_NONE, DDSPF_DXT1 }, // D3DFMT_DXT1 - { DXGI_FORMAT_BC2_UNORM, CONV_FLAGS_NONE, DDSPF_DXT3 }, // D3DFMT_DXT3 - { DXGI_FORMAT_BC3_UNORM, CONV_FLAGS_NONE, DDSPF_DXT5 }, // D3DFMT_DXT5 - - { DXGI_FORMAT_BC2_UNORM, CONV_FLAGS_PMALPHA, DDSPF_DXT2 }, // D3DFMT_DXT2 - { DXGI_FORMAT_BC3_UNORM, CONV_FLAGS_PMALPHA, DDSPF_DXT4 }, // D3DFMT_DXT4 - - { DXGI_FORMAT_BC4_UNORM, CONV_FLAGS_NONE, DDSPF_BC4_UNORM }, - { DXGI_FORMAT_BC4_SNORM, CONV_FLAGS_NONE, DDSPF_BC4_SNORM }, - { DXGI_FORMAT_BC5_UNORM, CONV_FLAGS_NONE, DDSPF_BC5_UNORM }, - { DXGI_FORMAT_BC5_SNORM, CONV_FLAGS_NONE, DDSPF_BC5_SNORM }, - - { DXGI_FORMAT_BC4_UNORM, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC( 'A', 'T', 'I', '1' ), 0, 0, 0, 0, 0 } }, - { DXGI_FORMAT_BC5_UNORM, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC( 'A', 'T', 'I', '2' ), 0, 0, 0, 0, 0 } }, - - { DXGI_FORMAT_R8G8_B8G8_UNORM, CONV_FLAGS_NONE, DDSPF_R8G8_B8G8 }, // D3DFMT_R8G8_B8G8 - { DXGI_FORMAT_G8R8_G8B8_UNORM, CONV_FLAGS_NONE, DDSPF_G8R8_G8B8 }, // D3DFMT_G8R8_G8B8 - - { DXGI_FORMAT_B8G8R8A8_UNORM, CONV_FLAGS_NONE, DDSPF_A8R8G8B8 }, // D3DFMT_A8R8G8B8 (uses DXGI 1.1 format) - { DXGI_FORMAT_B8G8R8X8_UNORM, CONV_FLAGS_NONE, DDSPF_X8R8G8B8 }, // D3DFMT_X8R8G8B8 (uses DXGI 1.1 format) - { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_NONE, DDSPF_A8B8G8R8 }, // D3DFMT_A8B8G8R8 - { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_NOALPHA, DDSPF_X8B8G8R8 }, // D3DFMT_X8B8G8R8 - { DXGI_FORMAT_R16G16_UNORM, CONV_FLAGS_NONE, DDSPF_G16R16 }, // D3DFMT_G16R16 - - { DXGI_FORMAT_R10G10B10A2_UNORM, CONV_FLAGS_SWIZZLE, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000 } }, // D3DFMT_A2R10G10B10 (D3DX reversal issue workaround) - { DXGI_FORMAT_R10G10B10A2_UNORM, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 } }, // D3DFMT_A2B10G10R10 (D3DX reversal issue workaround) - - { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_EXPAND - | CONV_FLAGS_NOALPHA - | CONV_FLAGS_888, DDSPF_R8G8B8 }, // D3DFMT_R8G8B8 - - { DXGI_FORMAT_B5G6R5_UNORM, CONV_FLAGS_565, DDSPF_R5G6B5 }, // D3DFMT_R5G6B5 - { DXGI_FORMAT_B5G5R5A1_UNORM, CONV_FLAGS_5551, DDSPF_A1R5G5B5 }, // D3DFMT_A1R5G5B5 - { DXGI_FORMAT_B5G5R5A1_UNORM, CONV_FLAGS_5551 - | CONV_FLAGS_NOALPHA, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x0000 } }, // D3DFMT_X1R5G5B5 - - { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_EXPAND - | CONV_FLAGS_8332, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x00e0, 0x001c, 0x0003, 0xff00 } }, // D3DFMT_A8R3G3B2 - { DXGI_FORMAT_B5G6R5_UNORM, CONV_FLAGS_EXPAND - | CONV_FLAGS_332, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 8, 0xe0, 0x1c, 0x03, 0x00 } }, // D3DFMT_R3G3B2 - - { DXGI_FORMAT_R8_UNORM, CONV_FLAGS_NONE, DDSPF_L8 }, // D3DFMT_L8 - { DXGI_FORMAT_R16_UNORM, CONV_FLAGS_NONE, DDSPF_L16 }, // D3DFMT_L16 - { DXGI_FORMAT_R8G8_UNORM, CONV_FLAGS_NONE, DDSPF_A8L8 }, // D3DFMT_A8L8 - - { DXGI_FORMAT_A8_UNORM, CONV_FLAGS_NONE, DDSPF_A8 }, // D3DFMT_A8 - - { DXGI_FORMAT_R16G16B16A16_UNORM, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 36, 0, 0, 0, 0, 0 } }, // D3DFMT_A16B16G16R16 - { DXGI_FORMAT_R16G16B16A16_SNORM, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 110, 0, 0, 0, 0, 0 } }, // D3DFMT_Q16W16V16U16 - { DXGI_FORMAT_R16_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 111, 0, 0, 0, 0, 0 } }, // D3DFMT_R16F - { DXGI_FORMAT_R16G16_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 112, 0, 0, 0, 0, 0 } }, // D3DFMT_G16R16F - { DXGI_FORMAT_R16G16B16A16_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 113, 0, 0, 0, 0, 0 } }, // D3DFMT_A16B16G16R16F - { DXGI_FORMAT_R32_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 114, 0, 0, 0, 0, 0 } }, // D3DFMT_R32F - { DXGI_FORMAT_R32G32_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 115, 0, 0, 0, 0, 0 } }, // D3DFMT_G32R32F - { DXGI_FORMAT_R32G32B32A32_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 116, 0, 0, 0, 0, 0 } }, // D3DFMT_A32B32G32R32F - - { DXGI_FORMAT_R32_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0xffffffff, 0x00000000, 0x00000000, 0x00000000 } }, // D3DFMT_R32F (D3DX uses FourCC 114 instead) - - { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_EXPAND - | CONV_FLAGS_PAL8 - | CONV_FLAGS_A8P8, { sizeof(DDS_PIXELFORMAT), DDS_PAL8, 0, 16, 0, 0, 0, 0 } }, // D3DFMT_A8P8 - { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_EXPAND - | CONV_FLAGS_PAL8, { sizeof(DDS_PIXELFORMAT), DDS_PAL8, 0, 8, 0, 0, 0, 0 } }, // D3DFMT_P8 - - { DXGI_FORMAT_B4G4R4A4_UNORM, CONV_FLAGS_4444, DDSPF_A4R4G4B4 }, // D3DFMT_A4R4G4B4 (uses DXGI 1.2 format) - { DXGI_FORMAT_B4G4R4A4_UNORM, CONV_FLAGS_NOALPHA - | 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) - - { DXGI_FORMAT_R8G8_SNORM, CONV_FLAGS_NONE, DDSPF_V8U8 }, // D3DFMT_V8U8 - { DXGI_FORMAT_R8G8B8A8_SNORM, CONV_FLAGS_NONE, DDSPF_Q8W8V8U8 }, // D3DFMT_Q8W8V8U8 - { DXGI_FORMAT_R16G16_SNORM, CONV_FLAGS_NONE, DDSPF_V16U16 }, // D3DFMT_V16U16 -}; - -// Note that many common DDS reader/writers (including D3DX) swap the -// the RED/BLUE masks for 10:10:10:2 formats. We assumme -// below that the 'backwards' header mask is being used since it is most -// likely written by D3DX. The more robust solution is to use the 'DX10' -// header extension and specify the DXGI_FORMAT_R10G10B10A2_UNORM format directly - -// We do not support the following legacy Direct3D 9 formats: -// BumpDuDv D3DFMT_A2W10V10U10 -// BumpLuminance D3DFMT_L6V5U5, D3DFMT_X8L8V8U8 -// FourCC 117 D3DFMT_CxV8U8 -// ZBuffer D3DFMT_D16_LOCKABLE -// FourCC 82 D3DFMT_D32F_LOCKABLE - -static DXGI_FORMAT _GetDXGIFormat( const DDS_PIXELFORMAT& ddpf, DWORD flags, _Inout_ DWORD& convFlags ) -{ - const size_t MAP_SIZE = sizeof(g_LegacyDDSMap) / sizeof(LegacyDDS); - size_t index = 0; - for( index = 0; index < MAP_SIZE; ++index ) + //------------------------------------------------------------------------------------- + // Legacy format mapping table (used for DDS files without 'DX10' extended header) + //------------------------------------------------------------------------------------- + enum CONVERSION_FLAGS { - const LegacyDDS* entry = &g_LegacyDDSMap[index]; + CONV_FLAGS_NONE = 0x0, + CONV_FLAGS_EXPAND = 0x1, // Conversion requires expanded pixel size + CONV_FLAGS_NOALPHA = 0x2, // Conversion requires setting alpha to known value + CONV_FLAGS_SWIZZLE = 0x4, // BGR/RGB order swizzling required + CONV_FLAGS_PAL8 = 0x8, // Has an 8-bit palette + CONV_FLAGS_888 = 0x10, // Source is an 8:8:8 (24bpp) format + CONV_FLAGS_565 = 0x20, // Source is a 5:6:5 (16bpp) format + CONV_FLAGS_5551 = 0x40, // Source is a 5:5:5:1 (16bpp) format + CONV_FLAGS_4444 = 0x80, // Source is a 4:4:4:4 (16bpp) format + CONV_FLAGS_44 = 0x100, // Source is a 4:4 (8bpp) format + CONV_FLAGS_332 = 0x200, // Source is a 3:3:2 (8bpp) format + CONV_FLAGS_8332 = 0x400, // Source is a 8:3:3:2 (16bpp) format + CONV_FLAGS_A8P8 = 0x800, // Has an 8-bit palette with an alpha channel + CONV_FLAGS_DX10 = 0x10000, // Has the 'DX10' extension header + CONV_FLAGS_PMALPHA = 0x20000, // Contains premultiplied alpha data + CONV_FLAGS_L8 = 0x40000, // Source is a 8 luminance format + CONV_FLAGS_L16 = 0x80000, // Source is a 16 luminance format + CONV_FLAGS_A8L8 = 0x100000, // Source is a 8:8 luminance format + }; - if ( ddpf.dwFlags & entry->ddpf.dwFlags ) + struct LegacyDDS + { + DXGI_FORMAT format; + DWORD convFlags; + DDS_PIXELFORMAT ddpf; + }; + + const LegacyDDS g_LegacyDDSMap[] = + { + { DXGI_FORMAT_BC1_UNORM, CONV_FLAGS_NONE, DDSPF_DXT1 }, // D3DFMT_DXT1 + { DXGI_FORMAT_BC2_UNORM, CONV_FLAGS_NONE, DDSPF_DXT3 }, // D3DFMT_DXT3 + { DXGI_FORMAT_BC3_UNORM, CONV_FLAGS_NONE, DDSPF_DXT5 }, // D3DFMT_DXT5 + + { DXGI_FORMAT_BC2_UNORM, CONV_FLAGS_PMALPHA, DDSPF_DXT2 }, // D3DFMT_DXT2 + { DXGI_FORMAT_BC3_UNORM, CONV_FLAGS_PMALPHA, DDSPF_DXT4 }, // D3DFMT_DXT4 + + { DXGI_FORMAT_BC4_UNORM, CONV_FLAGS_NONE, DDSPF_BC4_UNORM }, + { DXGI_FORMAT_BC4_SNORM, CONV_FLAGS_NONE, DDSPF_BC4_SNORM }, + { DXGI_FORMAT_BC5_UNORM, CONV_FLAGS_NONE, DDSPF_BC5_UNORM }, + { DXGI_FORMAT_BC5_SNORM, CONV_FLAGS_NONE, DDSPF_BC5_SNORM }, + + { DXGI_FORMAT_BC4_UNORM, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'T', 'I', '1'), 0, 0, 0, 0, 0 } }, + { DXGI_FORMAT_BC5_UNORM, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'T', 'I', '2'), 0, 0, 0, 0, 0 } }, + + { DXGI_FORMAT_R8G8_B8G8_UNORM, CONV_FLAGS_NONE, DDSPF_R8G8_B8G8 }, // D3DFMT_R8G8_B8G8 + { DXGI_FORMAT_G8R8_G8B8_UNORM, CONV_FLAGS_NONE, DDSPF_G8R8_G8B8 }, // D3DFMT_G8R8_G8B8 + + { DXGI_FORMAT_B8G8R8A8_UNORM, CONV_FLAGS_NONE, DDSPF_A8R8G8B8 }, // D3DFMT_A8R8G8B8 (uses DXGI 1.1 format) + { DXGI_FORMAT_B8G8R8X8_UNORM, CONV_FLAGS_NONE, DDSPF_X8R8G8B8 }, // D3DFMT_X8R8G8B8 (uses DXGI 1.1 format) + { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_NONE, DDSPF_A8B8G8R8 }, // D3DFMT_A8B8G8R8 + { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_NOALPHA, DDSPF_X8B8G8R8 }, // D3DFMT_X8B8G8R8 + { DXGI_FORMAT_R16G16_UNORM, CONV_FLAGS_NONE, DDSPF_G16R16 }, // D3DFMT_G16R16 + + { DXGI_FORMAT_R10G10B10A2_UNORM, CONV_FLAGS_SWIZZLE, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000 } }, // D3DFMT_A2R10G10B10 (D3DX reversal issue workaround) + { DXGI_FORMAT_R10G10B10A2_UNORM, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 } }, // D3DFMT_A2B10G10R10 (D3DX reversal issue workaround) + + { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_EXPAND + | CONV_FLAGS_NOALPHA + | CONV_FLAGS_888, DDSPF_R8G8B8 }, // D3DFMT_R8G8B8 + + { DXGI_FORMAT_B5G6R5_UNORM, CONV_FLAGS_565, DDSPF_R5G6B5 }, // D3DFMT_R5G6B5 + { DXGI_FORMAT_B5G5R5A1_UNORM, CONV_FLAGS_5551, DDSPF_A1R5G5B5 }, // D3DFMT_A1R5G5B5 + { DXGI_FORMAT_B5G5R5A1_UNORM, CONV_FLAGS_5551 + | CONV_FLAGS_NOALPHA, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x0000 } }, // D3DFMT_X1R5G5B5 + + { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_EXPAND + | CONV_FLAGS_8332, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x00e0, 0x001c, 0x0003, 0xff00 } }, // D3DFMT_A8R3G3B2 + { DXGI_FORMAT_B5G6R5_UNORM, CONV_FLAGS_EXPAND + | CONV_FLAGS_332, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 8, 0xe0, 0x1c, 0x03, 0x00 } }, // D3DFMT_R3G3B2 + + { DXGI_FORMAT_R8_UNORM, CONV_FLAGS_NONE, DDSPF_L8 }, // D3DFMT_L8 + { DXGI_FORMAT_R16_UNORM, CONV_FLAGS_NONE, DDSPF_L16 }, // D3DFMT_L16 + { DXGI_FORMAT_R8G8_UNORM, CONV_FLAGS_NONE, DDSPF_A8L8 }, // D3DFMT_A8L8 + + { DXGI_FORMAT_A8_UNORM, CONV_FLAGS_NONE, DDSPF_A8 }, // D3DFMT_A8 + + { DXGI_FORMAT_R16G16B16A16_UNORM, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 36, 0, 0, 0, 0, 0 } }, // D3DFMT_A16B16G16R16 + { DXGI_FORMAT_R16G16B16A16_SNORM, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 110, 0, 0, 0, 0, 0 } }, // D3DFMT_Q16W16V16U16 + { DXGI_FORMAT_R16_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 111, 0, 0, 0, 0, 0 } }, // D3DFMT_R16F + { DXGI_FORMAT_R16G16_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 112, 0, 0, 0, 0, 0 } }, // D3DFMT_G16R16F + { DXGI_FORMAT_R16G16B16A16_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 113, 0, 0, 0, 0, 0 } }, // D3DFMT_A16B16G16R16F + { DXGI_FORMAT_R32_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 114, 0, 0, 0, 0, 0 } }, // D3DFMT_R32F + { DXGI_FORMAT_R32G32_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 115, 0, 0, 0, 0, 0 } }, // D3DFMT_G32R32F + { DXGI_FORMAT_R32G32B32A32_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 116, 0, 0, 0, 0, 0 } }, // D3DFMT_A32B32G32R32F + + { DXGI_FORMAT_R32_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0xffffffff, 0x00000000, 0x00000000, 0x00000000 } }, // D3DFMT_R32F (D3DX uses FourCC 114 instead) + + { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_EXPAND + | CONV_FLAGS_PAL8 + | CONV_FLAGS_A8P8, { sizeof(DDS_PIXELFORMAT), DDS_PAL8, 0, 16, 0, 0, 0, 0 } }, // D3DFMT_A8P8 + { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_EXPAND + | CONV_FLAGS_PAL8, { sizeof(DDS_PIXELFORMAT), DDS_PAL8, 0, 8, 0, 0, 0, 0 } }, // D3DFMT_P8 + + { DXGI_FORMAT_B4G4R4A4_UNORM, CONV_FLAGS_4444, DDSPF_A4R4G4B4 }, // D3DFMT_A4R4G4B4 (uses DXGI 1.2 format) + { DXGI_FORMAT_B4G4R4A4_UNORM, CONV_FLAGS_NOALPHA + | 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) + + { DXGI_FORMAT_R8G8_SNORM, CONV_FLAGS_NONE, DDSPF_V8U8 }, // D3DFMT_V8U8 + { DXGI_FORMAT_R8G8B8A8_SNORM, CONV_FLAGS_NONE, DDSPF_Q8W8V8U8 }, // D3DFMT_Q8W8V8U8 + { DXGI_FORMAT_R16G16_SNORM, CONV_FLAGS_NONE, DDSPF_V16U16 }, // D3DFMT_V16U16 + }; + + // Note that many common DDS reader/writers (including D3DX) swap the + // the RED/BLUE masks for 10:10:10:2 formats. We assumme + // below that the 'backwards' header mask is being used since it is most + // likely written by D3DX. The more robust solution is to use the 'DX10' + // header extension and specify the DXGI_FORMAT_R10G10B10A2_UNORM format directly + + // We do not support the following legacy Direct3D 9 formats: + // BumpDuDv D3DFMT_A2W10V10U10 + // BumpLuminance D3DFMT_L6V5U5, D3DFMT_X8L8V8U8 + // FourCC 117 D3DFMT_CxV8U8 + // ZBuffer D3DFMT_D16_LOCKABLE + // FourCC 82 D3DFMT_D32F_LOCKABLE + + DXGI_FORMAT GetDXGIFormat(const DDS_PIXELFORMAT& ddpf, DWORD flags, _Inout_ DWORD& convFlags) + { + const size_t MAP_SIZE = sizeof(g_LegacyDDSMap) / sizeof(LegacyDDS); + size_t index = 0; + for (index = 0; index < MAP_SIZE; ++index) { - if ( entry->ddpf.dwFlags & DDS_FOURCC ) + const LegacyDDS* entry = &g_LegacyDDSMap[index]; + + if (ddpf.dwFlags & entry->ddpf.dwFlags) { - if ( ddpf.dwFourCC == entry->ddpf.dwFourCC ) - break; - } - else if ( entry->ddpf.dwFlags & DDS_PAL8 ) - { - if ( ddpf.dwRGBBitCount == entry->ddpf.dwRGBBitCount ) - break; - } - else if ( ddpf.dwRGBBitCount == entry->ddpf.dwRGBBitCount ) - { - // RGB, RGBA, ALPHA, LUMINANCE - if ( ddpf.dwRBitMask == entry->ddpf.dwRBitMask - && ddpf.dwGBitMask == entry->ddpf.dwGBitMask - && ddpf.dwBBitMask == entry->ddpf.dwBBitMask - && ddpf.dwABitMask == entry->ddpf.dwABitMask ) - break; + if (entry->ddpf.dwFlags & DDS_FOURCC) + { + if (ddpf.dwFourCC == entry->ddpf.dwFourCC) + break; + } + else if (entry->ddpf.dwFlags & DDS_PAL8) + { + if (ddpf.dwRGBBitCount == entry->ddpf.dwRGBBitCount) + break; + } + else if (ddpf.dwRGBBitCount == entry->ddpf.dwRGBBitCount) + { + // RGB, RGBA, ALPHA, LUMINANCE + if (ddpf.dwRBitMask == entry->ddpf.dwRBitMask + && ddpf.dwGBitMask == entry->ddpf.dwGBitMask + && ddpf.dwBBitMask == entry->ddpf.dwBBitMask + && ddpf.dwABitMask == entry->ddpf.dwABitMask) + break; + } } } + + if (index >= MAP_SIZE) + return DXGI_FORMAT_UNKNOWN; + + DWORD cflags = g_LegacyDDSMap[index].convFlags; + DXGI_FORMAT format = g_LegacyDDSMap[index].format; + + if ((cflags & CONV_FLAGS_EXPAND) && (flags & DDS_FLAGS_NO_LEGACY_EXPANSION)) + return DXGI_FORMAT_UNKNOWN; + + if ((format == DXGI_FORMAT_R10G10B10A2_UNORM) && (flags & DDS_FLAGS_NO_R10B10G10A2_FIXUP)) + { + cflags ^= CONV_FLAGS_SWIZZLE; + } + + convFlags = cflags; + + return format; } - if ( index >= MAP_SIZE ) - return DXGI_FORMAT_UNKNOWN; - DWORD cflags = g_LegacyDDSMap[index].convFlags; - DXGI_FORMAT format = g_LegacyDDSMap[index].format; - - if ( (cflags & CONV_FLAGS_EXPAND) && (flags & DDS_FLAGS_NO_LEGACY_EXPANSION) ) - return DXGI_FORMAT_UNKNOWN; - - if ( (format == DXGI_FORMAT_R10G10B10A2_UNORM) && (flags & DDS_FLAGS_NO_R10B10G10A2_FIXUP) ) + //------------------------------------------------------------------------------------- + // Decodes DDS header including optional DX10 extended header + //------------------------------------------------------------------------------------- + HRESULT DecodeDDSHeader( + _In_reads_bytes_(size) const void* pSource, + size_t size, + DWORD flags, + _Out_ TexMetadata& metadata, + _Inout_ DWORD& convFlags) { - cflags ^= CONV_FLAGS_SWIZZLE; - } + if (!pSource) + return E_INVALIDARG; - convFlags = cflags; + memset(&metadata, 0, sizeof(TexMetadata)); - return format; -} + if (size < (sizeof(DDS_HEADER) + sizeof(uint32_t))) + { + return HRESULT_FROM_WIN32(ERROR_INVALID_DATA); + } - -//------------------------------------------------------------------------------------- -// Decodes DDS header including optional DX10 extended header -//------------------------------------------------------------------------------------- -static HRESULT _DecodeDDSHeader( _In_reads_bytes_(size) LPCVOID pSource, size_t size, DWORD flags, _Out_ TexMetadata& metadata, - _Inout_ DWORD& convFlags ) -{ - if ( !pSource ) - return E_INVALIDARG; - - memset( &metadata, 0, sizeof(TexMetadata) ); - - if ( size < (sizeof(DDS_HEADER) + sizeof(uint32_t)) ) - { - return HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); - } - - // DDS files always start with the same magic number ("DDS ") - uint32_t dwMagicNumber = *reinterpret_cast(pSource); - if ( dwMagicNumber != DDS_MAGIC ) - { - return E_FAIL; - } - - auto pHeader = reinterpret_cast( (const uint8_t*)pSource + sizeof( uint32_t ) ); - - // Verify header to validate DDS file - if ( pHeader->dwSize != sizeof(DDS_HEADER) - || pHeader->ddspf.dwSize != sizeof(DDS_PIXELFORMAT) ) - { - return E_FAIL; - } - - metadata.mipLevels = pHeader->dwMipMapCount; - if ( metadata.mipLevels == 0 ) - metadata.mipLevels = 1; - - // Check for DX10 extension - if ( (pHeader->ddspf.dwFlags & DDS_FOURCC) - && (MAKEFOURCC( 'D', 'X', '1', '0' ) == pHeader->ddspf.dwFourCC) ) - { - // Buffer must be big enough for both headers and magic value - if ( size < ( sizeof(DDS_HEADER) + sizeof(uint32_t) + sizeof(DDS_HEADER_DXT10) ) ) + // DDS files always start with the same magic number ("DDS ") + uint32_t dwMagicNumber = *reinterpret_cast(pSource); + if (dwMagicNumber != DDS_MAGIC) { return E_FAIL; } - auto d3d10ext = reinterpret_cast( (const uint8_t*)pSource + sizeof( uint32_t ) + sizeof(DDS_HEADER) ); - convFlags |= CONV_FLAGS_DX10; + auto pHeader = reinterpret_cast((const uint8_t*)pSource + sizeof(uint32_t)); - metadata.arraySize = d3d10ext->arraySize; - if ( metadata.arraySize == 0 ) + // Verify header to validate DDS file + if (pHeader->dwSize != sizeof(DDS_HEADER) + || pHeader->ddspf.dwSize != sizeof(DDS_PIXELFORMAT)) { - return HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); + return E_FAIL; } - metadata.format = d3d10ext->dxgiFormat; - if ( !IsValid( metadata.format ) || IsPalettized( metadata.format ) ) + metadata.mipLevels = pHeader->dwMipMapCount; + if (metadata.mipLevels == 0) + metadata.mipLevels = 1; + + // Check for DX10 extension + if ((pHeader->ddspf.dwFlags & DDS_FOURCC) + && (MAKEFOURCC('D', 'X', '1', '0') == pHeader->ddspf.dwFourCC)) { - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); - } - - static_assert( TEX_MISC_TEXTURECUBE == DDS_RESOURCE_MISC_TEXTURECUBE, "DDS header mismatch"); - - metadata.miscFlags = d3d10ext->miscFlag & ~TEX_MISC_TEXTURECUBE; - - switch ( d3d10ext->resourceDimension ) - { - case DDS_DIMENSION_TEXTURE1D: - - // D3DX writes 1D textures with a fixed Height of 1 - if ( (pHeader->dwFlags & DDS_HEIGHT) && pHeader->dwHeight != 1 ) + // Buffer must be big enough for both headers and magic value + if (size < (sizeof(DDS_HEADER) + sizeof(uint32_t) + sizeof(DDS_HEADER_DXT10))) { - return HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); + return E_FAIL; } - metadata.width = pHeader->dwWidth; - metadata.height = 1; - metadata.depth = 1; - metadata.dimension = TEX_DIMENSION_TEXTURE1D; - break; + auto d3d10ext = reinterpret_cast((const uint8_t*)pSource + sizeof(uint32_t) + sizeof(DDS_HEADER)); + convFlags |= CONV_FLAGS_DX10; - case DDS_DIMENSION_TEXTURE2D: - if ( d3d10ext->miscFlag & DDS_RESOURCE_MISC_TEXTURECUBE ) + metadata.arraySize = d3d10ext->arraySize; + if (metadata.arraySize == 0) { - metadata.miscFlags |= TEX_MISC_TEXTURECUBE; - metadata.arraySize *= 6; + return HRESULT_FROM_WIN32(ERROR_INVALID_DATA); } - metadata.width = pHeader->dwWidth; - metadata.height = pHeader->dwHeight; - metadata.depth = 1; - metadata.dimension = TEX_DIMENSION_TEXTURE2D; - break; - - case DDS_DIMENSION_TEXTURE3D: - if ( !(pHeader->dwFlags & DDS_HEADER_FLAGS_VOLUME) ) + metadata.format = d3d10ext->dxgiFormat; + if (!IsValid(metadata.format) || IsPalettized(metadata.format)) { - return HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } - if ( metadata.arraySize > 1 ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + static_assert(TEX_MISC_TEXTURECUBE == DDS_RESOURCE_MISC_TEXTURECUBE, "DDS header mismatch"); - metadata.width = pHeader->dwWidth; - metadata.height = pHeader->dwHeight; - metadata.depth = pHeader->dwDepth; - metadata.dimension = TEX_DIMENSION_TEXTURE3D; - break; + metadata.miscFlags = d3d10ext->miscFlag & ~TEX_MISC_TEXTURECUBE; - default: - return HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); - } - - static_assert( TEX_MISC2_ALPHA_MODE_MASK == DDS_MISC_FLAGS2_ALPHA_MODE_MASK, "DDS header mismatch"); - - static_assert( TEX_ALPHA_MODE_UNKNOWN == DDS_ALPHA_MODE_UNKNOWN, "DDS header mismatch"); - static_assert( TEX_ALPHA_MODE_STRAIGHT == DDS_ALPHA_MODE_STRAIGHT, "DDS header mismatch"); - static_assert( TEX_ALPHA_MODE_PREMULTIPLIED == DDS_ALPHA_MODE_PREMULTIPLIED, "DDS header mismatch"); - static_assert( TEX_ALPHA_MODE_OPAQUE == DDS_ALPHA_MODE_OPAQUE, "DDS header mismatch"); - static_assert( TEX_ALPHA_MODE_CUSTOM == DDS_ALPHA_MODE_CUSTOM, "DDS header mismatch"); - - metadata.miscFlags2 = d3d10ext->miscFlags2; - } - else - { - metadata.arraySize = 1; - - if ( pHeader->dwFlags & DDS_HEADER_FLAGS_VOLUME ) - { - metadata.width = pHeader->dwWidth; - metadata.height = pHeader->dwHeight; - metadata.depth = pHeader->dwDepth; - metadata.dimension = TEX_DIMENSION_TEXTURE3D; - } - else - { - if ( pHeader->dwCaps2 & DDS_CUBEMAP ) + switch (d3d10ext->resourceDimension) { - // We require all six faces to be defined - if ( (pHeader->dwCaps2 & DDS_CUBEMAP_ALLFACES ) != DDS_CUBEMAP_ALLFACES ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + case DDS_DIMENSION_TEXTURE1D: - metadata.arraySize = 6; - metadata.miscFlags |= TEX_MISC_TEXTURECUBE; + // D3DX writes 1D textures with a fixed Height of 1 + if ((pHeader->dwFlags & DDS_HEIGHT) && pHeader->dwHeight != 1) + { + return HRESULT_FROM_WIN32(ERROR_INVALID_DATA); + } + + metadata.width = pHeader->dwWidth; + metadata.height = 1; + metadata.depth = 1; + metadata.dimension = TEX_DIMENSION_TEXTURE1D; + break; + + case DDS_DIMENSION_TEXTURE2D: + if (d3d10ext->miscFlag & DDS_RESOURCE_MISC_TEXTURECUBE) + { + metadata.miscFlags |= TEX_MISC_TEXTURECUBE; + metadata.arraySize *= 6; + } + + metadata.width = pHeader->dwWidth; + metadata.height = pHeader->dwHeight; + metadata.depth = 1; + metadata.dimension = TEX_DIMENSION_TEXTURE2D; + break; + + case DDS_DIMENSION_TEXTURE3D: + if (!(pHeader->dwFlags & DDS_HEADER_FLAGS_VOLUME)) + { + return HRESULT_FROM_WIN32(ERROR_INVALID_DATA); + } + + if (metadata.arraySize > 1) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + + metadata.width = pHeader->dwWidth; + metadata.height = pHeader->dwHeight; + metadata.depth = pHeader->dwDepth; + metadata.dimension = TEX_DIMENSION_TEXTURE3D; + break; + + default: + return HRESULT_FROM_WIN32(ERROR_INVALID_DATA); } - metadata.width = pHeader->dwWidth; - metadata.height = pHeader->dwHeight; - metadata.depth = 1; - metadata.dimension = TEX_DIMENSION_TEXTURE2D; + static_assert(TEX_MISC2_ALPHA_MODE_MASK == DDS_MISC_FLAGS2_ALPHA_MODE_MASK, "DDS header mismatch"); - // Note there's no way for a legacy Direct3D 9 DDS to express a '1D' texture + static_assert(TEX_ALPHA_MODE_UNKNOWN == DDS_ALPHA_MODE_UNKNOWN, "DDS header mismatch"); + static_assert(TEX_ALPHA_MODE_STRAIGHT == DDS_ALPHA_MODE_STRAIGHT, "DDS header mismatch"); + static_assert(TEX_ALPHA_MODE_PREMULTIPLIED == DDS_ALPHA_MODE_PREMULTIPLIED, "DDS header mismatch"); + static_assert(TEX_ALPHA_MODE_OPAQUE == DDS_ALPHA_MODE_OPAQUE, "DDS header mismatch"); + static_assert(TEX_ALPHA_MODE_CUSTOM == DDS_ALPHA_MODE_CUSTOM, "DDS header mismatch"); + + metadata.miscFlags2 = d3d10ext->miscFlags2; + } + else + { + metadata.arraySize = 1; + + if (pHeader->dwFlags & DDS_HEADER_FLAGS_VOLUME) + { + metadata.width = pHeader->dwWidth; + metadata.height = pHeader->dwHeight; + metadata.depth = pHeader->dwDepth; + metadata.dimension = TEX_DIMENSION_TEXTURE3D; + } + else + { + if (pHeader->dwCaps2 & DDS_CUBEMAP) + { + // We require all six faces to be defined + if ((pHeader->dwCaps2 & DDS_CUBEMAP_ALLFACES) != DDS_CUBEMAP_ALLFACES) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + + metadata.arraySize = 6; + metadata.miscFlags |= TEX_MISC_TEXTURECUBE; + } + + metadata.width = pHeader->dwWidth; + metadata.height = pHeader->dwHeight; + metadata.depth = 1; + metadata.dimension = TEX_DIMENSION_TEXTURE2D; + + // Note there's no way for a legacy Direct3D 9 DDS to express a '1D' texture + } + + metadata.format = GetDXGIFormat(pHeader->ddspf, flags, convFlags); + + if (metadata.format == DXGI_FORMAT_UNKNOWN) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + + if (convFlags & CONV_FLAGS_PMALPHA) + metadata.miscFlags2 |= TEX_ALPHA_MODE_PREMULTIPLIED; + + // Special flag for handling LUMINANCE legacy formats + if (flags & DDS_FLAGS_EXPAND_LUMINANCE) + { + switch (metadata.format) + { + case DXGI_FORMAT_R8_UNORM: + metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM; + convFlags |= CONV_FLAGS_L8 | CONV_FLAGS_EXPAND; + break; + + case DXGI_FORMAT_R8G8_UNORM: + metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM; + convFlags |= CONV_FLAGS_A8L8 | CONV_FLAGS_EXPAND; + break; + + case DXGI_FORMAT_R16_UNORM: + metadata.format = DXGI_FORMAT_R16G16B16A16_UNORM; + convFlags |= CONV_FLAGS_L16 | CONV_FLAGS_EXPAND; + break; + } + } } - metadata.format = _GetDXGIFormat( pHeader->ddspf, flags, convFlags ); - - if ( metadata.format == DXGI_FORMAT_UNKNOWN ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); - - if ( convFlags & CONV_FLAGS_PMALPHA ) - metadata.miscFlags2 |= TEX_ALPHA_MODE_PREMULTIPLIED; - - // Special flag for handling LUMINANCE legacy formats - if ( flags & DDS_FLAGS_EXPAND_LUMINANCE ) + // Special flag for handling BGR DXGI 1.1 formats + if (flags & DDS_FLAGS_FORCE_RGB) { - switch ( metadata.format ) + switch (metadata.format) { - case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM: metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM; - convFlags |= CONV_FLAGS_L8 | CONV_FLAGS_EXPAND; + convFlags |= CONV_FLAGS_SWIZZLE; break; - case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM: metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM; - convFlags |= CONV_FLAGS_A8L8 | CONV_FLAGS_EXPAND; + convFlags |= CONV_FLAGS_SWIZZLE | CONV_FLAGS_NOALPHA; break; - case DXGI_FORMAT_R16_UNORM: - metadata.format = DXGI_FORMAT_R16G16B16A16_UNORM; - convFlags |= CONV_FLAGS_L16 | CONV_FLAGS_EXPAND; + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + metadata.format = DXGI_FORMAT_R8G8B8A8_TYPELESS; + convFlags |= CONV_FLAGS_SWIZZLE; + break; + + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + convFlags |= CONV_FLAGS_SWIZZLE; + break; + + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + metadata.format = DXGI_FORMAT_R8G8B8A8_TYPELESS; + convFlags |= CONV_FLAGS_SWIZZLE | CONV_FLAGS_NOALPHA; + break; + + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + convFlags |= CONV_FLAGS_SWIZZLE | CONV_FLAGS_NOALPHA; break; } } - } - // Special flag for handling BGR DXGI 1.1 formats - if (flags & DDS_FLAGS_FORCE_RGB) - { - switch ( metadata.format ) + // Special flag for handling 16bpp formats + if (flags & DDS_FLAGS_NO_16BPP) { - case DXGI_FORMAT_B8G8R8A8_UNORM: - metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM; - convFlags |= CONV_FLAGS_SWIZZLE; - break; - - case DXGI_FORMAT_B8G8R8X8_UNORM: - metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM; - convFlags |= CONV_FLAGS_SWIZZLE | CONV_FLAGS_NOALPHA; - break; - - case DXGI_FORMAT_B8G8R8A8_TYPELESS: - metadata.format = DXGI_FORMAT_R8G8B8A8_TYPELESS; - convFlags |= CONV_FLAGS_SWIZZLE; - break; - - case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: - metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; - convFlags |= CONV_FLAGS_SWIZZLE; - break; - - case DXGI_FORMAT_B8G8R8X8_TYPELESS: - metadata.format = DXGI_FORMAT_R8G8B8A8_TYPELESS; - convFlags |= CONV_FLAGS_SWIZZLE | CONV_FLAGS_NOALPHA; - break; - - case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: - metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; - convFlags |= CONV_FLAGS_SWIZZLE | CONV_FLAGS_NOALPHA; - break; + switch (metadata.format) + { + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_B5G5R5A1_UNORM: + case DXGI_FORMAT_B4G4R4A4_UNORM: + metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM; + convFlags |= CONV_FLAGS_EXPAND; + if (metadata.format == DXGI_FORMAT_B5G6R5_UNORM) + convFlags |= CONV_FLAGS_NOALPHA; + } } - } - // Special flag for handling 16bpp formats - if (flags & DDS_FLAGS_NO_16BPP) - { - switch ( metadata.format ) - { - case DXGI_FORMAT_B5G6R5_UNORM: - case DXGI_FORMAT_B5G5R5A1_UNORM: - case DXGI_FORMAT_B4G4R4A4_UNORM: - metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM; - convFlags |= CONV_FLAGS_EXPAND; - if ( metadata.format == DXGI_FORMAT_B5G6R5_UNORM ) - convFlags |= CONV_FLAGS_NOALPHA; - } + return S_OK; } - - return S_OK; } @@ -469,58 +472,62 @@ static HRESULT _DecodeDDSHeader( _In_reads_bytes_(size) LPCVOID pSource, size_t // Encodes DDS file header (magic value, header, optional DX10 extended header) //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT _EncodeDDSHeader( const TexMetadata& metadata, DWORD flags, - LPVOID pDestination, size_t maxsize, size_t& required ) +HRESULT DirectX::_EncodeDDSHeader( + const TexMetadata& metadata, + DWORD flags, + void* pDestination, + size_t maxsize, + size_t& required) { - if ( !IsValid( metadata.format ) ) + if (!IsValid(metadata.format)) return E_INVALIDARG; - if ( IsPalettized( metadata.format ) ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if (IsPalettized(metadata.format)) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); - if ( metadata.arraySize > 1 ) + if (metadata.arraySize > 1) { - if ( (metadata.arraySize != 6) || (metadata.dimension != TEX_DIMENSION_TEXTURE2D) || !(metadata.IsCubemap()) ) + if ((metadata.arraySize != 6) || (metadata.dimension != TEX_DIMENSION_TEXTURE2D) || !(metadata.IsCubemap())) { // Texture1D arrays, Texture2D arrays, and Cubemap arrays must be stored using 'DX10' extended header flags |= DDS_FLAGS_FORCE_DX10_EXT; } } - if ( flags & DDS_FLAGS_FORCE_DX10_EXT_MISC2 ) + if (flags & DDS_FLAGS_FORCE_DX10_EXT_MISC2) { flags |= DDS_FLAGS_FORCE_DX10_EXT; } DDS_PIXELFORMAT ddpf = { 0 }; - if ( !(flags & DDS_FLAGS_FORCE_DX10_EXT) ) + if (!(flags & DDS_FLAGS_FORCE_DX10_EXT)) { - switch( metadata.format ) + switch (metadata.format) { - case DXGI_FORMAT_R8G8B8A8_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_A8B8G8R8, sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_R16G16_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_G16R16, sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_R8G8_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_A8L8, sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_R16_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_L16, sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_R8_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_L8, sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_A8_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_A8, sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_R8G8_B8G8_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_R8G8_B8G8, sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_G8R8_G8B8_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_G8R8_G8B8, sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_BC1_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_DXT1, sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_BC2_UNORM: memcpy_s( &ddpf, sizeof(ddpf), metadata.IsPMAlpha() ? (&DDSPF_DXT2) : (&DDSPF_DXT3), sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_BC3_UNORM: memcpy_s( &ddpf, sizeof(ddpf), metadata.IsPMAlpha() ? (&DDSPF_DXT4) : (&DDSPF_DXT5), sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_BC4_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_BC4_UNORM, sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_BC4_SNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_BC4_SNORM, sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_BC5_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_BC5_UNORM, sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_BC5_SNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_BC5_SNORM, sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_B5G6R5_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_R5G6B5, sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_B5G5R5A1_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_A1R5G5B5, sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_R8G8_SNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_V8U8, sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_R8G8B8A8_SNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_Q8W8V8U8, sizeof(DDS_PIXELFORMAT) ); break; - case DXGI_FORMAT_R16G16_SNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_V16U16, 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; // DXGI 1.2 - case DXGI_FORMAT_YUY2: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_YUY2, sizeof(DDS_PIXELFORMAT) ); break; // DXGI 1.2 + case DXGI_FORMAT_R8G8B8A8_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_A8B8G8R8, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_R16G16_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_G16R16, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_R8G8_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_A8L8, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_R16_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_L16, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_R8_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_L8, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_A8_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_A8, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_R8G8_B8G8_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_R8G8_B8G8, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_G8R8_G8B8_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_G8R8_G8B8, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_BC1_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_DXT1, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_BC2_UNORM: memcpy_s(&ddpf, sizeof(ddpf), metadata.IsPMAlpha() ? (&DDSPF_DXT2) : (&DDSPF_DXT3), sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_BC3_UNORM: memcpy_s(&ddpf, sizeof(ddpf), metadata.IsPMAlpha() ? (&DDSPF_DXT4) : (&DDSPF_DXT5), sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_BC4_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_BC4_UNORM, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_BC4_SNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_BC4_SNORM, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_BC5_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_BC5_UNORM, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_BC5_SNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_BC5_SNORM, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_B5G6R5_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_R5G6B5, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_B5G5R5A1_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_A1R5G5B5, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_R8G8_SNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_V8U8, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_R8G8B8A8_SNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_Q8W8V8U8, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_R16G16_SNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_V16U16, 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; // 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: @@ -538,7 +545,7 @@ HRESULT _EncodeDDSHeader( const TexMetadata& metadata, DWORD flags, case DXGI_FORMAT_R32G32_FLOAT: ddpf.dwSize = sizeof(DDS_PIXELFORMAT); ddpf.dwFlags = DDS_FOURCC; ddpf.dwFourCC = 115; // D3DFMT_G32R32F break; - case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_FLOAT: ddpf.dwSize = sizeof(DDS_PIXELFORMAT); ddpf.dwFlags = DDS_FOURCC; ddpf.dwFourCC = 112; // D3DFMT_G16R16F break; case DXGI_FORMAT_R32_FLOAT: @@ -552,22 +559,22 @@ HRESULT _EncodeDDSHeader( const TexMetadata& metadata, DWORD flags, required = sizeof(uint32_t) + sizeof(DDS_HEADER); - if ( ddpf.dwSize == 0 ) + if (ddpf.dwSize == 0) required += sizeof(DDS_HEADER_DXT10); - if ( !pDestination ) + if (!pDestination) return S_OK; - if ( maxsize < required ) + if (maxsize < required) return E_NOT_SUFFICIENT_BUFFER; *reinterpret_cast(pDestination) = DDS_MAGIC; - auto header = reinterpret_cast( reinterpret_cast(pDestination) + sizeof(uint32_t) ); - assert( header ); + auto header = reinterpret_cast(reinterpret_cast(pDestination) + sizeof(uint32_t)); + assert(header); - memset( header, 0, sizeof(DDS_HEADER ) ); - header->dwSize = sizeof( DDS_HEADER ); + memset(header, 0, sizeof(DDS_HEADER)); + header->dwSize = sizeof(DDS_HEADER); header->dwFlags = DDS_HEADER_FLAGS_TEXTURE; header->dwCaps = DDS_SURFACE_FLAGS_TEXTURE; @@ -575,35 +582,35 @@ HRESULT _EncodeDDSHeader( const TexMetadata& metadata, DWORD flags, { header->dwFlags |= DDS_HEADER_FLAGS_MIPMAP; - if ( metadata.mipLevels > UINT32_MAX ) + if (metadata.mipLevels > UINT32_MAX) return E_INVALIDARG; - header->dwMipMapCount = static_cast( metadata.mipLevels ); + header->dwMipMapCount = static_cast(metadata.mipLevels); - if ( header->dwMipMapCount > 1 ) + if (header->dwMipMapCount > 1) header->dwCaps |= DDS_SURFACE_FLAGS_MIPMAP; } - switch( metadata.dimension ) + switch (metadata.dimension) { case TEX_DIMENSION_TEXTURE1D: - if ( metadata.width > UINT32_MAX ) + if (metadata.width > UINT32_MAX) return E_INVALIDARG; - header->dwWidth = static_cast( metadata.width ); + header->dwWidth = static_cast(metadata.width); header->dwHeight = header->dwDepth = 1; break; case TEX_DIMENSION_TEXTURE2D: - if ( metadata.height > UINT32_MAX - || metadata.width > UINT32_MAX ) + if (metadata.height > UINT32_MAX + || metadata.width > UINT32_MAX) return E_INVALIDARG; - header->dwHeight = static_cast( metadata.height ); - header->dwWidth = static_cast( metadata.width ); + header->dwHeight = static_cast(metadata.height); + header->dwWidth = static_cast(metadata.width); header->dwDepth = 1; - if ( metadata.IsCubemap() ) + if (metadata.IsCubemap()) { header->dwCaps |= DDS_SURFACE_FLAGS_CUBEMAP; header->dwCaps2 |= DDS_CUBEMAP_ALLFACES; @@ -611,16 +618,16 @@ HRESULT _EncodeDDSHeader( const TexMetadata& metadata, DWORD flags, break; case TEX_DIMENSION_TEXTURE3D: - if ( metadata.height > UINT32_MAX - || metadata.width > UINT32_MAX - || metadata.depth > UINT32_MAX ) + if (metadata.height > UINT32_MAX + || metadata.width > UINT32_MAX + || metadata.depth > UINT32_MAX) return E_INVALIDARG; header->dwFlags |= DDS_HEADER_FLAGS_VOLUME; header->dwCaps2 |= DDS_FLAGS_VOLUME; - header->dwHeight = static_cast( metadata.height ); - header->dwWidth = static_cast( metadata.width ); - header->dwDepth = static_cast( metadata.depth ); + header->dwHeight = static_cast(metadata.height); + header->dwWidth = static_cast(metadata.width); + header->dwDepth = static_cast(metadata.depth); break; default: @@ -628,61 +635,61 @@ HRESULT _EncodeDDSHeader( const TexMetadata& metadata, DWORD flags, } size_t rowPitch, slicePitch; - ComputePitch( metadata.format, metadata.width, metadata.height, rowPitch, slicePitch, CP_FLAGS_NONE ); + ComputePitch(metadata.format, metadata.width, metadata.height, rowPitch, slicePitch, CP_FLAGS_NONE); - if ( slicePitch > UINT32_MAX - || rowPitch > UINT32_MAX ) + if (slicePitch > UINT32_MAX + || rowPitch > UINT32_MAX) return E_FAIL; - if ( IsCompressed( metadata.format ) ) + if (IsCompressed(metadata.format)) { header->dwFlags |= DDS_HEADER_FLAGS_LINEARSIZE; - header->dwPitchOrLinearSize = static_cast( slicePitch ); + header->dwPitchOrLinearSize = static_cast(slicePitch); } else { header->dwFlags |= DDS_HEADER_FLAGS_PITCH; - header->dwPitchOrLinearSize = static_cast( rowPitch ); + header->dwPitchOrLinearSize = static_cast(rowPitch); } - if ( ddpf.dwSize == 0 ) + if (ddpf.dwSize == 0) { - memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_DX10, sizeof(DDS_PIXELFORMAT) ); + memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_DX10, sizeof(DDS_PIXELFORMAT)); - auto ext = reinterpret_cast( reinterpret_cast(header) + sizeof(DDS_HEADER) ); - assert( ext ); + auto ext = reinterpret_cast(reinterpret_cast(header) + sizeof(DDS_HEADER)); + assert(ext); - memset( ext, 0, sizeof(DDS_HEADER_DXT10) ); + memset(ext, 0, sizeof(DDS_HEADER_DXT10)); ext->dxgiFormat = metadata.format; ext->resourceDimension = metadata.dimension; - if ( metadata.arraySize > UINT32_MAX ) + if (metadata.arraySize > UINT32_MAX) return E_INVALIDARG; - static_assert( TEX_MISC_TEXTURECUBE == DDS_RESOURCE_MISC_TEXTURECUBE, "DDS header mismatch"); - + static_assert(TEX_MISC_TEXTURECUBE == DDS_RESOURCE_MISC_TEXTURECUBE, "DDS header mismatch"); + ext->miscFlag = metadata.miscFlags & ~TEX_MISC_TEXTURECUBE; - if ( metadata.miscFlags & TEX_MISC_TEXTURECUBE ) + if (metadata.miscFlags & TEX_MISC_TEXTURECUBE) { ext->miscFlag |= TEX_MISC_TEXTURECUBE; - assert( (metadata.arraySize % 6) == 0 ); - ext->arraySize = static_cast( metadata.arraySize / 6 ); + assert((metadata.arraySize % 6) == 0); + ext->arraySize = static_cast(metadata.arraySize / 6); } else { - ext->arraySize = static_cast( metadata.arraySize ); + ext->arraySize = static_cast(metadata.arraySize); } - static_assert( TEX_MISC2_ALPHA_MODE_MASK == DDS_MISC_FLAGS2_ALPHA_MODE_MASK, "DDS header mismatch"); + static_assert(TEX_MISC2_ALPHA_MODE_MASK == DDS_MISC_FLAGS2_ALPHA_MODE_MASK, "DDS header mismatch"); - static_assert( TEX_ALPHA_MODE_UNKNOWN == DDS_ALPHA_MODE_UNKNOWN, "DDS header mismatch"); - static_assert( TEX_ALPHA_MODE_STRAIGHT == DDS_ALPHA_MODE_STRAIGHT, "DDS header mismatch"); - static_assert( TEX_ALPHA_MODE_PREMULTIPLIED == DDS_ALPHA_MODE_PREMULTIPLIED, "DDS header mismatch"); - static_assert( TEX_ALPHA_MODE_OPAQUE == DDS_ALPHA_MODE_OPAQUE, "DDS header mismatch"); - static_assert( TEX_ALPHA_MODE_CUSTOM == DDS_ALPHA_MODE_CUSTOM, "DDS header mismatch"); + static_assert(TEX_ALPHA_MODE_UNKNOWN == DDS_ALPHA_MODE_UNKNOWN, "DDS header mismatch"); + static_assert(TEX_ALPHA_MODE_STRAIGHT == DDS_ALPHA_MODE_STRAIGHT, "DDS header mismatch"); + static_assert(TEX_ALPHA_MODE_PREMULTIPLIED == DDS_ALPHA_MODE_PREMULTIPLIED, "DDS header mismatch"); + static_assert(TEX_ALPHA_MODE_OPAQUE == DDS_ALPHA_MODE_OPAQUE, "DDS header mismatch"); + static_assert(TEX_ALPHA_MODE_CUSTOM == DDS_ALPHA_MODE_CUSTOM, "DDS header mismatch"); - if ( flags & DDS_FLAGS_FORCE_DX10_EXT_MISC2 ) + if (flags & DDS_FLAGS_FORCE_DX10_EXT_MISC2) { // This was formerly 'reserved'. D3DX10 and D3DX11 will fail if this value is anything other than 0 ext->miscFlags2 = metadata.miscFlags2; @@ -690,112 +697,303 @@ HRESULT _EncodeDDSHeader( const TexMetadata& metadata, DWORD flags, } else { - memcpy_s( &header->ddspf, sizeof(header->ddspf), &ddpf, sizeof(ddpf) ); + memcpy_s(&header->ddspf, sizeof(header->ddspf), &ddpf, sizeof(ddpf)); } return S_OK; } -//------------------------------------------------------------------------------------- -// Converts an image row with optional clearing of alpha value to 1.0 -// Returns true if supported, false if expansion case not supported -//------------------------------------------------------------------------------------- -enum TEXP_LEGACY_FORMAT +namespace { - TEXP_LEGACY_UNKNOWN = 0, - TEXP_LEGACY_R8G8B8, - TEXP_LEGACY_R3G3B2, - TEXP_LEGACY_A8R3G3B2, - TEXP_LEGACY_P8, - TEXP_LEGACY_A8P8, - TEXP_LEGACY_A4L4, - TEXP_LEGACY_B4G4R4A4, - TEXP_LEGACY_L8, - TEXP_LEGACY_L16, - TEXP_LEGACY_A8L8 -}; - -inline static TEXP_LEGACY_FORMAT _FindLegacyFormat( DWORD flags ) -{ - TEXP_LEGACY_FORMAT lformat = TEXP_LEGACY_UNKNOWN; - - if ( flags & CONV_FLAGS_PAL8 ) + //------------------------------------------------------------------------------------- + // Converts an image row with optional clearing of alpha value to 1.0 + // Returns true if supported, false if expansion case not supported + //------------------------------------------------------------------------------------- + enum TEXP_LEGACY_FORMAT { - lformat = ( flags & CONV_FLAGS_A8P8 ) ? TEXP_LEGACY_A8P8 : TEXP_LEGACY_P8; + TEXP_LEGACY_UNKNOWN = 0, + TEXP_LEGACY_R8G8B8, + TEXP_LEGACY_R3G3B2, + TEXP_LEGACY_A8R3G3B2, + TEXP_LEGACY_P8, + TEXP_LEGACY_A8P8, + TEXP_LEGACY_A4L4, + TEXP_LEGACY_B4G4R4A4, + TEXP_LEGACY_L8, + TEXP_LEGACY_L16, + TEXP_LEGACY_A8L8 + }; + + inline TEXP_LEGACY_FORMAT _FindLegacyFormat(DWORD flags) + { + TEXP_LEGACY_FORMAT lformat = TEXP_LEGACY_UNKNOWN; + + if (flags & CONV_FLAGS_PAL8) + { + lformat = (flags & CONV_FLAGS_A8P8) ? TEXP_LEGACY_A8P8 : TEXP_LEGACY_P8; + } + else if (flags & CONV_FLAGS_888) + lformat = TEXP_LEGACY_R8G8B8; + else if (flags & CONV_FLAGS_332) + lformat = TEXP_LEGACY_R3G3B2; + else if (flags & CONV_FLAGS_8332) + lformat = TEXP_LEGACY_A8R3G3B2; + else if (flags & CONV_FLAGS_44) + lformat = TEXP_LEGACY_A4L4; + else if (flags & CONV_FLAGS_4444) + lformat = TEXP_LEGACY_B4G4R4A4; + else if (flags & CONV_FLAGS_L8) + lformat = TEXP_LEGACY_L8; + else if (flags & CONV_FLAGS_L16) + lformat = TEXP_LEGACY_L16; + else if (flags & CONV_FLAGS_A8L8) + lformat = TEXP_LEGACY_A8L8; + + return lformat; } - else if ( flags & CONV_FLAGS_888 ) - lformat = TEXP_LEGACY_R8G8B8; - else if ( flags & CONV_FLAGS_332 ) - lformat = TEXP_LEGACY_R3G3B2; - else if ( flags & CONV_FLAGS_8332 ) - lformat = TEXP_LEGACY_A8R3G3B2; - else if ( flags & CONV_FLAGS_44 ) - lformat = TEXP_LEGACY_A4L4; - else if ( flags & CONV_FLAGS_4444 ) - lformat = TEXP_LEGACY_B4G4R4A4; - else if ( flags & CONV_FLAGS_L8 ) - lformat = TEXP_LEGACY_L8; - else if ( flags & CONV_FLAGS_L16 ) - lformat = TEXP_LEGACY_L16; - else if ( flags & CONV_FLAGS_A8L8 ) - lformat = TEXP_LEGACY_A8L8; - return lformat; -} - -_Success_(return != false) -static bool _LegacyExpandScanline( _Out_writes_bytes_(outSize) LPVOID pDestination, size_t outSize, _In_ DXGI_FORMAT outFormat, - _In_reads_bytes_(inSize) LPCVOID pSource, size_t inSize, _In_ TEXP_LEGACY_FORMAT inFormat, - _In_reads_opt_(256) const uint32_t* pal8, _In_ DWORD flags ) -{ - assert( pDestination && outSize > 0 ); - assert( pSource && inSize > 0 ); - assert( IsValid(outFormat) && !IsPlanar(outFormat) && !IsPalettized(outFormat) ); - - switch( inFormat ) + _Success_(return != false) + bool LegacyExpandScanline( + _Out_writes_bytes_(outSize) void* pDestination, + size_t outSize, + _In_ DXGI_FORMAT outFormat, + _In_reads_bytes_(inSize) const void* pSource, + size_t inSize, + _In_ TEXP_LEGACY_FORMAT inFormat, + _In_reads_opt_(256) const uint32_t* pal8, + _In_ DWORD flags) { - case TEXP_LEGACY_R8G8B8: - if ( outFormat != DXGI_FORMAT_R8G8B8A8_UNORM ) + assert(pDestination && outSize > 0); + assert(pSource && inSize > 0); + assert(IsValid(outFormat) && !IsPlanar(outFormat) && !IsPalettized(outFormat)); + + switch (inFormat) + { + case TEXP_LEGACY_R8G8B8: + if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) + return false; + + // D3DFMT_R8G8B8 -> DXGI_FORMAT_R8G8B8A8_UNORM + if (inSize >= 3 && outSize >= 4) + { + const uint8_t * __restrict sPtr = reinterpret_cast(pSource); + uint32_t * __restrict dPtr = reinterpret_cast(pDestination); + + for (size_t ocount = 0, icount = 0; ((icount < (inSize - 2)) && (ocount < (outSize - 3))); icount += 3, ocount += 4) + { + // 24bpp Direct3D 9 files are actually BGR, so need to swizzle as well + uint32_t t1 = (*(sPtr) << 16); + uint32_t t2 = (*(sPtr + 1) << 8); + uint32_t t3 = *(sPtr + 2); + + *(dPtr++) = t1 | t2 | t3 | 0xff000000; + sPtr += 3; + } + return true; + } return false; - // D3DFMT_R8G8B8 -> DXGI_FORMAT_R8G8B8A8_UNORM - if ( inSize >= 3 && outSize >= 4 ) - { - const uint8_t * __restrict sPtr = reinterpret_cast(pSource); - uint32_t * __restrict dPtr = reinterpret_cast(pDestination); - - for( size_t ocount = 0, icount = 0; ( ( icount < ( inSize - 2 ) ) && ( ocount < ( outSize - 3 ) ) ); icount += 3, ocount += 4 ) + case TEXP_LEGACY_R3G3B2: + switch (outFormat) { - // 24bpp Direct3D 9 files are actually BGR, so need to swizzle as well - uint32_t t1 = ( *(sPtr) << 16 ); - uint32_t t2 = ( *(sPtr+1) << 8 ); - uint32_t t3 = *(sPtr+2); + case DXGI_FORMAT_R8G8B8A8_UNORM: + // D3DFMT_R3G3B2 -> DXGI_FORMAT_R8G8B8A8_UNORM + if (inSize >= 1 && outSize >= 4) + { + const uint8_t* __restrict sPtr = reinterpret_cast(pSource); + uint32_t * __restrict dPtr = reinterpret_cast(pDestination); - *(dPtr++) = t1 | t2 | t3 | 0xff000000; - sPtr += 3; + for (size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 3))); ++icount, ocount += 4) + { + uint8_t t = *(sPtr++); + + uint32_t t1 = (t & 0xe0) | ((t & 0xe0) >> 3) | ((t & 0xc0) >> 6); + uint32_t t2 = ((t & 0x1c) << 11) | ((t & 0x1c) << 8) | ((t & 0x18) << 5); + uint32_t t3 = ((t & 0x03) << 22) | ((t & 0x03) << 20) | ((t & 0x03) << 18) | ((t & 0x03) << 16); + + *(dPtr++) = t1 | t2 | t3 | 0xff000000; + } + return true; + } + return false; + + case DXGI_FORMAT_B5G6R5_UNORM: + // D3DFMT_R3G3B2 -> DXGI_FORMAT_B5G6R5_UNORM + if (inSize >= 1 && outSize >= 2) + { + const uint8_t* __restrict sPtr = reinterpret_cast(pSource); + uint16_t * __restrict dPtr = reinterpret_cast(pDestination); + + for (size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 1))); ++icount, ocount += 2) + { + uint8_t t = *(sPtr++); + + uint16_t t1 = ((t & 0xe0) << 8) | ((t & 0xc0) << 5); + uint16_t t2 = ((t & 0x1c) << 6) | ((t & 0x1c) << 3); + uint16_t t3 = ((t & 0x03) << 3) | ((t & 0x03) << 1) | ((t & 0x02) >> 1); + + *(dPtr++) = t1 | t2 | t3; + } + return true; + } + return false; } - return true; - } - return false; + break; - case TEXP_LEGACY_R3G3B2: - switch( outFormat ) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: - // D3DFMT_R3G3B2 -> DXGI_FORMAT_R8G8B8A8_UNORM - if ( inSize >= 1 && outSize >= 4 ) + case TEXP_LEGACY_A8R3G3B2: + if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) + return false; + + // D3DFMT_A8R3G3B2 -> DXGI_FORMAT_R8G8B8A8_UNORM + if (inSize >= 2 && outSize >= 4) + { + const uint16_t* __restrict sPtr = reinterpret_cast(pSource); + uint32_t * __restrict dPtr = reinterpret_cast(pDestination); + + for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4) + { + uint16_t t = *(sPtr++); + + uint32_t t1 = (t & 0x00e0) | ((t & 0x00e0) >> 3) | ((t & 0x00c0) >> 6); + uint32_t t2 = ((t & 0x001c) << 11) | ((t & 0x001c) << 8) | ((t & 0x0018) << 5); + uint32_t t3 = ((t & 0x0003) << 22) | ((t & 0x0003) << 20) | ((t & 0x0003) << 18) | ((t & 0x0003) << 16); + uint32_t ta = (flags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : ((t & 0xff00) << 16); + + *(dPtr++) = t1 | t2 | t3 | ta; + } + return true; + } + return false; + + case TEXP_LEGACY_P8: + if ((outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) || !pal8) + return false; + + // D3DFMT_P8 -> DXGI_FORMAT_R8G8B8A8_UNORM + if (inSize >= 1 && outSize >= 4) { const uint8_t* __restrict sPtr = reinterpret_cast(pSource); uint32_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t ocount = 0, icount = 0; ( ( icount < inSize ) && ( ocount < ( outSize - 3 ) ) ); ++icount, ocount += 4 ) + for (size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 3))); ++icount, ocount += 4) { uint8_t t = *(sPtr++); - uint32_t t1 = (t & 0xe0) | ((t & 0xe0) >> 3) | ((t & 0xc0) >> 6); - uint32_t t2 = ((t & 0x1c) << 11) | ((t & 0x1c) << 8) | ((t & 0x18) << 5); - uint32_t t3 = ((t & 0x03) << 22) | ((t & 0x03) << 20) | ((t & 0x03) << 18) | ((t & 0x03) << 16); + *(dPtr++) = pal8[t]; + } + return true; + } + return false; + + case TEXP_LEGACY_A8P8: + if ((outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) || !pal8) + return false; + + // D3DFMT_A8P8 -> DXGI_FORMAT_R8G8B8A8_UNORM + if (inSize >= 2 && outSize >= 4) + { + const uint16_t* __restrict sPtr = reinterpret_cast(pSource); + uint32_t * __restrict dPtr = reinterpret_cast(pDestination); + + for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4) + { + uint16_t t = *(sPtr++); + + uint32_t t1 = pal8[t & 0xff]; + uint32_t ta = (flags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : ((t & 0xff00) << 16); + + *(dPtr++) = t1 | ta; + } + return true; + } + return false; + + case TEXP_LEGACY_A4L4: + switch (outFormat) + { + case DXGI_FORMAT_B4G4R4A4_UNORM: + // D3DFMT_A4L4 -> DXGI_FORMAT_B4G4R4A4_UNORM + if (inSize >= 1 && outSize >= 2) + { + const uint8_t * __restrict sPtr = reinterpret_cast(pSource); + uint16_t * __restrict dPtr = reinterpret_cast(pDestination); + + for (size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 1))); ++icount, ocount += 2) + { + uint8_t t = *(sPtr++); + + uint16_t t1 = (t & 0x0f); + uint16_t ta = (flags & TEXP_SCANLINE_SETALPHA) ? 0xf000 : ((t & 0xf0) << 8); + + *(dPtr++) = t1 | (t1 << 4) | (t1 << 8) | ta; + } + return true; + } + return false; + + case DXGI_FORMAT_R8G8B8A8_UNORM: + // D3DFMT_A4L4 -> DXGI_FORMAT_R8G8B8A8_UNORM + if (inSize >= 1 && outSize >= 4) + { + const uint8_t * __restrict sPtr = reinterpret_cast(pSource); + uint32_t * __restrict dPtr = reinterpret_cast(pDestination); + + for (size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 3))); ++icount, ocount += 4) + { + uint8_t t = *(sPtr++); + + uint32_t t1 = ((t & 0x0f) << 4) | (t & 0x0f); + uint32_t ta = (flags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : (((t & 0xf0) << 24) | ((t & 0xf0) << 20)); + + *(dPtr++) = t1 | (t1 << 8) | (t1 << 16) | ta; + } + return true; + } + return false; + } + break; + + case TEXP_LEGACY_B4G4R4A4: + if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) + return false; + + // D3DFMT_A4R4G4B4 -> DXGI_FORMAT_R8G8B8A8_UNORM + if (inSize >= 2 && outSize >= 4) + { + const uint16_t * __restrict sPtr = reinterpret_cast(pSource); + uint32_t * __restrict dPtr = reinterpret_cast(pDestination); + + for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4) + { + uint16_t t = *(sPtr++); + + uint32_t t1 = ((t & 0x0f00) >> 4) | ((t & 0x0f00) >> 8); + uint32_t t2 = ((t & 0x00f0) << 8) | ((t & 0x00f0) << 4); + uint32_t t3 = ((t & 0x000f) << 20) | ((t & 0x000f) << 16); + uint32_t ta = (flags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : (((t & 0xf000) << 16) | ((t & 0xf000) << 12)); + + *(dPtr++) = t1 | t2 | t3 | ta; + } + return true; + } + return false; + + case TEXP_LEGACY_L8: + if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) + return false; + + // D3DFMT_L8 -> DXGI_FORMAT_R8G8B8A8_UNORM + if (inSize >= 1 && outSize >= 4) + { + const uint8_t * __restrict sPtr = reinterpret_cast(pSource); + uint32_t * __restrict dPtr = reinterpret_cast(pDestination); + + for (size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 3))); ++icount, ocount += 4) + { + uint32_t t1 = *(sPtr++); + uint32_t t2 = (t1 << 8); + uint32_t t3 = (t1 << 16); *(dPtr++) = t1 | t2 | t3 | 0xff000000; } @@ -803,381 +1001,204 @@ static bool _LegacyExpandScanline( _Out_writes_bytes_(outSize) LPVOID pDestinati } return false; - case DXGI_FORMAT_B5G6R5_UNORM: - // D3DFMT_R3G3B2 -> DXGI_FORMAT_B5G6R5_UNORM - if ( inSize >= 1 && outSize >= 2 ) - { - const uint8_t* __restrict sPtr = reinterpret_cast(pSource); - uint16_t * __restrict dPtr = reinterpret_cast(pDestination); + case TEXP_LEGACY_L16: + if (outFormat != DXGI_FORMAT_R16G16B16A16_UNORM) + return false; - for( size_t ocount = 0, icount = 0; ( ( icount < inSize ) && ( ocount < ( outSize - 1 ) ) ); ++icount, ocount += 2 ) + // D3DFMT_L16 -> DXGI_FORMAT_R16G16B16A16_UNORM + if (inSize >= 2 && outSize >= 8) + { + const uint16_t* __restrict sPtr = reinterpret_cast(pSource); + uint64_t * __restrict dPtr = reinterpret_cast(pDestination); + + for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 7))); icount += 2, ocount += 8) { - uint8_t t = *(sPtr++); + uint16_t t = *(sPtr++); - uint16_t t1 = ((t & 0xe0) << 8) | ((t & 0xc0) << 5); - uint16_t t2 = ((t & 0x1c) << 6) | ((t & 0x1c) << 3); - uint16_t t3 = ((t & 0x03) << 3) | ((t & 0x03) << 1) | ((t & 0x02) >> 1); + uint64_t t1 = t; + uint64_t t2 = (t1 << 16); + uint64_t t3 = (t1 << 32); - *(dPtr++) = t1 | t2 | t3; - } - return true; - } - return false; - } - break; - - case TEXP_LEGACY_A8R3G3B2: - if ( outFormat != DXGI_FORMAT_R8G8B8A8_UNORM ) - return false; - - // D3DFMT_A8R3G3B2 -> DXGI_FORMAT_R8G8B8A8_UNORM - if ( inSize >= 2 && outSize >= 4 ) - { - const uint16_t* __restrict sPtr = reinterpret_cast(pSource); - uint32_t * __restrict dPtr = reinterpret_cast(pDestination); - - for( size_t ocount = 0, icount = 0; ( ( icount < ( inSize - 1 ) ) && ( ocount < ( outSize - 3 ) ) ); icount += 2, ocount += 4 ) - { - uint16_t t = *(sPtr++); - - uint32_t t1 = (t & 0x00e0) | ((t & 0x00e0) >> 3) | ((t & 0x00c0) >> 6); - uint32_t t2 = ((t & 0x001c) << 11) | ((t & 0x001c) << 8) | ((t & 0x0018) << 5); - uint32_t t3 = ((t & 0x0003) << 22) | ((t & 0x0003) << 20) | ((t & 0x0003) << 18) | ((t & 0x0003) << 16); - uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : ((t & 0xff00) << 16); - - *(dPtr++) = t1 | t2 | t3 | ta; - } - return true; - } - return false; - - case TEXP_LEGACY_P8: - if ( (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) || !pal8 ) - return false; - - // D3DFMT_P8 -> DXGI_FORMAT_R8G8B8A8_UNORM - if ( inSize >= 1 && outSize >= 4 ) - { - const uint8_t* __restrict sPtr = reinterpret_cast(pSource); - uint32_t * __restrict dPtr = reinterpret_cast(pDestination); - - for( size_t ocount = 0, icount = 0; ( ( icount < inSize ) && ( ocount < ( outSize - 3 ) ) ); ++icount, ocount += 4 ) - { - uint8_t t = *(sPtr++); - - *(dPtr++) = pal8[ t ]; - } - return true; - } - return false; - - case TEXP_LEGACY_A8P8: - if ( (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) || !pal8 ) - return false; - - // D3DFMT_A8P8 -> DXGI_FORMAT_R8G8B8A8_UNORM - if ( inSize >= 2 && outSize >= 4 ) - { - const uint16_t* __restrict sPtr = reinterpret_cast(pSource); - uint32_t * __restrict dPtr = reinterpret_cast(pDestination); - - for( size_t ocount = 0, icount = 0; ( ( icount < ( inSize - 1 ) ) && ( ocount < ( outSize - 3 ) ) ); icount += 2, ocount += 4 ) - { - uint16_t t = *(sPtr++); - - uint32_t t1 = pal8[ t & 0xff ]; - uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : ((t & 0xff00) << 16); - - *(dPtr++) = t1 | ta; - } - return true; - } - return false; - - case TEXP_LEGACY_A4L4: - switch( outFormat ) - { - case DXGI_FORMAT_B4G4R4A4_UNORM : - // D3DFMT_A4L4 -> DXGI_FORMAT_B4G4R4A4_UNORM - if ( inSize >= 1 && outSize >= 2 ) - { - const uint8_t * __restrict sPtr = reinterpret_cast(pSource); - uint16_t * __restrict dPtr = reinterpret_cast(pDestination); - - for( size_t ocount = 0, icount = 0; ( ( icount < inSize ) && ( ocount < ( outSize - 1 ) ) ); ++icount, ocount += 2 ) - { - uint8_t t = *(sPtr++); - - uint16_t t1 = (t & 0x0f); - uint16_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xf000 : ((t & 0xf0) << 8); - - *(dPtr++) = t1 | (t1 << 4) | (t1 << 8) | ta; + *(dPtr++) = t1 | t2 | t3 | 0xffff000000000000; } return true; } return false; - case DXGI_FORMAT_R8G8B8A8_UNORM: - // D3DFMT_A4L4 -> DXGI_FORMAT_R8G8B8A8_UNORM - if ( inSize >= 1 && outSize >= 4 ) + case TEXP_LEGACY_A8L8: + if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) + return false; + + // D3DFMT_A8L8 -> DXGI_FORMAT_R8G8B8A8_UNORM + if (inSize >= 2 && outSize >= 4) { - const uint8_t * __restrict sPtr = reinterpret_cast(pSource); + const uint16_t* __restrict sPtr = reinterpret_cast(pSource); uint32_t * __restrict dPtr = reinterpret_cast(pDestination); - for( size_t ocount = 0, icount = 0; ( ( icount < inSize ) && ( ocount < ( outSize - 3 ) ) ); ++icount, ocount += 4 ) + for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4) { - uint8_t t = *(sPtr++); + uint16_t t = *(sPtr++); - uint32_t t1 = ((t & 0x0f) << 4) | (t & 0x0f); - uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : (((t & 0xf0) << 24) | ((t & 0xf0) << 20)); + uint32_t t1 = (t & 0xff); + uint32_t t2 = (t1 << 8); + uint32_t t3 = (t1 << 16); + uint32_t ta = (flags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : ((t & 0xff00) << 16); - *(dPtr++) = t1 | (t1 << 8) | (t1 << 16) | ta; + *(dPtr++) = t1 | t2 | t3 | ta; } return true; } return false; } - break; - case TEXP_LEGACY_B4G4R4A4: - if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) - return false; - - // D3DFMT_A4R4G4B4 -> DXGI_FORMAT_R8G8B8A8_UNORM - if ( inSize >= 2 && outSize >= 4 ) - { - const uint16_t * __restrict sPtr = reinterpret_cast(pSource); - uint32_t * __restrict dPtr = reinterpret_cast(pDestination); - - for( size_t ocount = 0, icount = 0; ( ( icount < ( inSize - 1 ) ) && ( ocount < ( outSize - 3 ) ) ); icount += 2, ocount += 4 ) - { - uint16_t t = *(sPtr++); - - uint32_t t1 = ((t & 0x0f00) >> 4) | ((t & 0x0f00) >> 8); - uint32_t t2 = ((t & 0x00f0) << 8) | ((t & 0x00f0) << 4); - uint32_t t3 = ((t & 0x000f) << 20) | ((t & 0x000f) << 16); - uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : (((t & 0xf000) << 16) | ((t & 0xf000) << 12)); - - *(dPtr++) = t1 | t2 | t3 | ta; - } - return true; - } - return false; - - case TEXP_LEGACY_L8: - if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) - return false; - - // D3DFMT_L8 -> DXGI_FORMAT_R8G8B8A8_UNORM - if ( inSize >= 1 && outSize >= 4 ) - { - const uint8_t * __restrict sPtr = reinterpret_cast(pSource); - uint32_t * __restrict dPtr = reinterpret_cast(pDestination); - - for( size_t ocount = 0, icount = 0; ( ( icount < inSize ) && ( ocount < ( outSize - 3 ) ) ); ++icount, ocount += 4 ) - { - uint32_t t1 = *(sPtr++); - uint32_t t2 = (t1 << 8); - uint32_t t3 = (t1 << 16); - - *(dPtr++) = t1 | t2 | t3 | 0xff000000; - } - return true; - } - return false; - - case TEXP_LEGACY_L16: - if (outFormat != DXGI_FORMAT_R16G16B16A16_UNORM) - return false; - - // D3DFMT_L16 -> DXGI_FORMAT_R16G16B16A16_UNORM - if ( inSize >= 2 && outSize >= 8 ) - { - const uint16_t* __restrict sPtr = reinterpret_cast(pSource); - uint64_t * __restrict dPtr = reinterpret_cast(pDestination); - - for( size_t ocount = 0, icount = 0; ( ( icount < ( inSize - 1 ) ) && ( ocount < ( outSize - 7 ) ) ); icount += 2, ocount += 8 ) - { - uint16_t t = *(sPtr++); - - uint64_t t1 = t; - uint64_t t2 = (t1 << 16); - uint64_t t3 = (t1 << 32); - - *(dPtr++) = t1 | t2 | t3 | 0xffff000000000000; - } - return true; - } - return false; - - case TEXP_LEGACY_A8L8: - if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) - return false; - - // D3DFMT_A8L8 -> DXGI_FORMAT_R8G8B8A8_UNORM - if ( inSize >= 2 && outSize >= 4 ) - { - const uint16_t* __restrict sPtr = reinterpret_cast(pSource); - uint32_t * __restrict dPtr = reinterpret_cast(pDestination); - - for( size_t ocount = 0, icount = 0; ( ( icount < ( inSize - 1 ) ) && ( ocount < ( outSize - 3 ) ) ); icount += 2, ocount += 4 ) - { - uint16_t t = *(sPtr++); - - uint32_t t1 = (t & 0xff); - uint32_t t2 = (t1 << 8); - uint32_t t3 = (t1 << 16); - uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : ((t & 0xff00) << 16); - - *(dPtr++) = t1 | t2 | t3 | ta; - } - return true; - } return false; } - return false; -} - -//------------------------------------------------------------------------------------- -// Converts or copies image data from pPixels into scratch image data -//------------------------------------------------------------------------------------- -static HRESULT _CopyImage( _In_reads_bytes_(size) const void* pPixels, _In_ size_t size, - _In_ const TexMetadata& metadata, _In_ DWORD cpFlags, _In_ DWORD convFlags, _In_reads_opt_(256) const uint32_t *pal8, _In_ const ScratchImage& image ) -{ - assert( pPixels ); - assert( image.GetPixels() ); - - if ( !size ) - return E_FAIL; - - if ( convFlags & CONV_FLAGS_EXPAND ) + //------------------------------------------------------------------------------------- + // Converts or copies image data from pPixels into scratch image data + //------------------------------------------------------------------------------------- + HRESULT CopyImage( + _In_reads_bytes_(size) const void* pPixels, + _In_ size_t size, + _In_ const TexMetadata& metadata, + _In_ DWORD cpFlags, + _In_ DWORD convFlags, + _In_reads_opt_(256) const uint32_t *pal8, + _In_ const ScratchImage& image) { - if ( convFlags & CONV_FLAGS_888 ) - cpFlags |= CP_FLAGS_24BPP; - else if ( convFlags & (CONV_FLAGS_565 | CONV_FLAGS_5551 | CONV_FLAGS_4444 | CONV_FLAGS_8332 | CONV_FLAGS_A8P8 | CONV_FLAGS_L16 | CONV_FLAGS_A8L8) ) - cpFlags |= CP_FLAGS_16BPP; - else if ( convFlags & (CONV_FLAGS_44 | CONV_FLAGS_332 | CONV_FLAGS_PAL8 | CONV_FLAGS_L8) ) - cpFlags |= CP_FLAGS_8BPP; - } + assert(pPixels); + assert(image.GetPixels()); - size_t pixelSize, nimages; - _DetermineImageArray( metadata, cpFlags, nimages, pixelSize ); - if ( (nimages == 0) || (nimages != image.GetImageCount()) ) - { - return E_FAIL; - } + if (!size) + return E_FAIL; - if (pixelSize > size) - { - return E_FAIL; - } + if (convFlags & CONV_FLAGS_EXPAND) + { + if (convFlags & CONV_FLAGS_888) + cpFlags |= CP_FLAGS_24BPP; + else if (convFlags & (CONV_FLAGS_565 | CONV_FLAGS_5551 | CONV_FLAGS_4444 | CONV_FLAGS_8332 | CONV_FLAGS_A8P8 | CONV_FLAGS_L16 | CONV_FLAGS_A8L8)) + cpFlags |= CP_FLAGS_16BPP; + else if (convFlags & (CONV_FLAGS_44 | CONV_FLAGS_332 | CONV_FLAGS_PAL8 | CONV_FLAGS_L8)) + cpFlags |= CP_FLAGS_8BPP; + } - std::unique_ptr timages( new (std::nothrow) Image[nimages] ); - if ( !timages ) - { - return E_OUTOFMEMORY; - } + size_t pixelSize, nimages; + _DetermineImageArray(metadata, cpFlags, nimages, pixelSize); + if ((nimages == 0) || (nimages != image.GetImageCount())) + { + return E_FAIL; + } - if ( !_SetupImageArray( (uint8_t*)pPixels, size, metadata, cpFlags, timages.get(), nimages ) ) - { - return E_FAIL; - } + if (pixelSize > size) + { + return E_FAIL; + } - if ( nimages != image.GetImageCount() ) - { - return E_FAIL; - } + std::unique_ptr timages(new (std::nothrow) Image[nimages]); + if (!timages) + { + return E_OUTOFMEMORY; + } - const Image* images = image.GetImages(); - if ( !images ) - { - return E_FAIL; - } + if (!_SetupImageArray((uint8_t*)pPixels, size, metadata, cpFlags, timages.get(), nimages)) + { + return E_FAIL; + } - DWORD tflags = (convFlags & CONV_FLAGS_NOALPHA) ? TEXP_SCANLINE_SETALPHA : 0; - if ( convFlags & CONV_FLAGS_SWIZZLE ) - tflags |= TEXP_SCANLINE_LEGACY; + if (nimages != image.GetImageCount()) + { + return E_FAIL; + } - switch (metadata.dimension) - { - case TEX_DIMENSION_TEXTURE1D: - case TEX_DIMENSION_TEXTURE2D: + const Image* images = image.GetImages(); + if (!images) + { + return E_FAIL; + } + + DWORD tflags = (convFlags & CONV_FLAGS_NOALPHA) ? TEXP_SCANLINE_SETALPHA : 0; + if (convFlags & CONV_FLAGS_SWIZZLE) + tflags |= TEXP_SCANLINE_LEGACY; + + switch (metadata.dimension) + { + case TEX_DIMENSION_TEXTURE1D: + case TEX_DIMENSION_TEXTURE2D: { size_t index = 0; - for( size_t item = 0; item < metadata.arraySize; ++item ) + for (size_t item = 0; item < metadata.arraySize; ++item) { - for( size_t level = 0; level < metadata.mipLevels; ++level, ++index ) + for (size_t level = 0; level < metadata.mipLevels; ++level, ++index) { - if ( index >= nimages ) + if (index >= nimages) return E_FAIL; - if ( images[ index ].height != timages[ index ].height ) + if (images[index].height != timages[index].height) return E_FAIL; - size_t dpitch = images[ index ].rowPitch; - size_t spitch = timages[ index ].rowPitch; + size_t dpitch = images[index].rowPitch; + size_t spitch = timages[index].rowPitch; - const uint8_t *pSrc = const_cast( timages[ index ].pixels ); - if ( !pSrc ) + const uint8_t *pSrc = const_cast(timages[index].pixels); + if (!pSrc) return E_POINTER; - uint8_t *pDest = images[ index ].pixels; - if ( !pDest ) + uint8_t *pDest = images[index].pixels; + if (!pDest) return E_POINTER; - if ( IsCompressed( metadata.format ) ) + if (IsCompressed(metadata.format)) { - size_t csize = std::min( images[ index ].slicePitch, timages[ index ].slicePitch ); - memcpy_s( pDest, images[ index ].slicePitch, pSrc, csize ); + size_t csize = std::min(images[index].slicePitch, timages[index].slicePitch); + memcpy_s(pDest, images[index].slicePitch, pSrc, csize); } - else if ( IsPlanar( metadata.format ) ) + else if (IsPlanar(metadata.format)) { - size_t count = ComputeScanlines( metadata.format, images[ index ].height ); - if ( !count ) + 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 ) + size_t csize = std::min(dpitch, spitch); + for (size_t h = 0; h < count; ++h) { - memcpy_s( pDest, dpitch, pSrc, csize ); + memcpy_s(pDest, dpitch, pSrc, csize); pSrc += spitch; pDest += dpitch; } } else { - for( size_t h = 0; h < images[ index ].height; ++h ) + for (size_t h = 0; h < images[index].height; ++h) { - if ( convFlags & CONV_FLAGS_EXPAND ) + if (convFlags & CONV_FLAGS_EXPAND) { - if ( convFlags & (CONV_FLAGS_565|CONV_FLAGS_5551|CONV_FLAGS_4444) ) + if (convFlags & (CONV_FLAGS_565 | CONV_FLAGS_5551 | CONV_FLAGS_4444)) { - if ( !_ExpandScanline( pDest, dpitch, DXGI_FORMAT_R8G8B8A8_UNORM, - pSrc, spitch, - (convFlags & CONV_FLAGS_565) ? DXGI_FORMAT_B5G6R5_UNORM : DXGI_FORMAT_B5G5R5A1_UNORM, - tflags ) ) + if (!_ExpandScanline(pDest, dpitch, DXGI_FORMAT_R8G8B8A8_UNORM, + pSrc, spitch, + (convFlags & CONV_FLAGS_565) ? DXGI_FORMAT_B5G6R5_UNORM : DXGI_FORMAT_B5G5R5A1_UNORM, + tflags)) return E_FAIL; } else { - TEXP_LEGACY_FORMAT lformat = _FindLegacyFormat( convFlags ); - if ( !_LegacyExpandScanline( pDest, dpitch, metadata.format, - pSrc, spitch, lformat, pal8, - tflags ) ) + TEXP_LEGACY_FORMAT lformat = _FindLegacyFormat(convFlags); + if (!LegacyExpandScanline(pDest, dpitch, metadata.format, + pSrc, spitch, lformat, pal8, + tflags)) return E_FAIL; } } - else if ( convFlags & CONV_FLAGS_SWIZZLE ) + else if (convFlags & CONV_FLAGS_SWIZZLE) { - _SwizzleScanline( pDest, dpitch, pSrc, spitch, - metadata.format, tflags ); + _SwizzleScanline(pDest, dpitch, pSrc, spitch, + metadata.format, tflags); } else { - _CopyScanline( pDest, dpitch, pSrc, spitch, - metadata.format, tflags ); + _CopyScanline(pDest, dpitch, pSrc, spitch, + metadata.format, tflags); } pSrc += spitch; @@ -1189,72 +1210,72 @@ static HRESULT _CopyImage( _In_reads_bytes_(size) const void* pPixels, _In_ size } break; - case TEX_DIMENSION_TEXTURE3D: + case TEX_DIMENSION_TEXTURE3D: { size_t index = 0; size_t d = metadata.depth; - for( size_t level = 0; level < metadata.mipLevels; ++level ) + for (size_t level = 0; level < metadata.mipLevels; ++level) { - for( size_t slice = 0; slice < d; ++slice, ++index ) + for (size_t slice = 0; slice < d; ++slice, ++index) { - if ( index >= nimages ) + if (index >= nimages) return E_FAIL; - if ( images[ index ].height != timages[ index ].height ) + if (images[index].height != timages[index].height) return E_FAIL; - size_t dpitch = images[ index ].rowPitch; - size_t spitch = timages[ index ].rowPitch; + size_t dpitch = images[index].rowPitch; + size_t spitch = timages[index].rowPitch; - const uint8_t *pSrc = const_cast( timages[ index ].pixels ); - if ( !pSrc ) + const uint8_t *pSrc = const_cast(timages[index].pixels); + if (!pSrc) return E_POINTER; - uint8_t *pDest = images[ index ].pixels; - if ( !pDest ) + uint8_t *pDest = images[index].pixels; + if (!pDest) return E_POINTER; - if ( IsCompressed( metadata.format ) ) + if (IsCompressed(metadata.format)) { - size_t csize = std::min( images[ index ].slicePitch, timages[ index ].slicePitch ); - memcpy_s( pDest, images[ index ].slicePitch, pSrc, csize ); + size_t csize = std::min(images[index].slicePitch, timages[index].slicePitch); + memcpy_s(pDest, images[index].slicePitch, pSrc, csize); } - else if ( IsPlanar( metadata.format ) ) + else if (IsPlanar(metadata.format)) { // Direct3D does not support any planar formats for Texture3D - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } else { - for( size_t h = 0; h < images[ index ].height; ++h ) + for (size_t h = 0; h < images[index].height; ++h) { - if ( convFlags & CONV_FLAGS_EXPAND ) + if (convFlags & CONV_FLAGS_EXPAND) { - if ( convFlags & (CONV_FLAGS_565|CONV_FLAGS_5551|CONV_FLAGS_4444) ) + if (convFlags & (CONV_FLAGS_565 | CONV_FLAGS_5551 | CONV_FLAGS_4444)) { - if ( !_ExpandScanline( pDest, dpitch, DXGI_FORMAT_R8G8B8A8_UNORM, - pSrc, spitch, - (convFlags & CONV_FLAGS_565) ? DXGI_FORMAT_B5G6R5_UNORM : DXGI_FORMAT_B5G5R5A1_UNORM, - tflags ) ) + if (!_ExpandScanline(pDest, dpitch, DXGI_FORMAT_R8G8B8A8_UNORM, + pSrc, spitch, + (convFlags & CONV_FLAGS_565) ? DXGI_FORMAT_B5G6R5_UNORM : DXGI_FORMAT_B5G5R5A1_UNORM, + tflags)) return E_FAIL; } else { - TEXP_LEGACY_FORMAT lformat = _FindLegacyFormat( convFlags ); - if ( !_LegacyExpandScanline( pDest, dpitch, metadata.format, - pSrc, spitch, lformat, pal8, - tflags ) ) + TEXP_LEGACY_FORMAT lformat = _FindLegacyFormat(convFlags); + if (!LegacyExpandScanline(pDest, dpitch, metadata.format, + pSrc, spitch, lformat, pal8, + tflags)) return E_FAIL; } } - else if ( convFlags & CONV_FLAGS_SWIZZLE ) + else if (convFlags & CONV_FLAGS_SWIZZLE) { - _SwizzleScanline( pDest, dpitch, pSrc, spitch, metadata.format, tflags ); + _SwizzleScanline(pDest, dpitch, pSrc, spitch, metadata.format, tflags); } else { - _CopyScanline( pDest, dpitch, pSrc, spitch, metadata.format, tflags ); + _CopyScanline(pDest, dpitch, pSrc, spitch, metadata.format, tflags); } pSrc += spitch; @@ -1263,62 +1284,63 @@ static HRESULT _CopyImage( _In_reads_bytes_(size) const void* pPixels, _In_ size } } - if ( d > 1 ) + if (d > 1) d >>= 1; } } break; - default: - return E_FAIL; - } - - return S_OK; -} - -static HRESULT _CopyImageInPlace( DWORD convFlags, _In_ const ScratchImage& image ) -{ - if ( !image.GetPixels() ) - return E_FAIL; - - const Image* images = image.GetImages(); - if ( !images ) - return E_FAIL; - - 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; - - for( size_t i = 0; i < image.GetImageCount(); ++i ) - { - const Image* img = &images[ i ]; - uint8_t *pPixels = img->pixels; - if ( !pPixels ) - return E_POINTER; - - size_t rowPitch = img->rowPitch; - - for( size_t h = 0; h < img->height; ++h ) - { - if ( convFlags & CONV_FLAGS_SWIZZLE ) - { - _SwizzleScanline( pPixels, rowPitch, pPixels, rowPitch, metadata.format, tflags ); - } - else - { - _CopyScanline( pPixels, rowPitch, pPixels, rowPitch, metadata.format, tflags ); - } - - pPixels += rowPitch; + default: + return E_FAIL; } + + return S_OK; } - return S_OK; + HRESULT CopyImageInPlace(DWORD convFlags, _In_ const ScratchImage& image) + { + if (!image.GetPixels()) + return E_FAIL; + + const Image* images = image.GetImages(); + if (!images) + return E_FAIL; + + 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; + + for (size_t i = 0; i < image.GetImageCount(); ++i) + { + const Image* img = &images[i]; + uint8_t *pPixels = img->pixels; + if (!pPixels) + return E_POINTER; + + size_t rowPitch = img->rowPitch; + + for (size_t h = 0; h < img->height; ++h) + { + if (convFlags & CONV_FLAGS_SWIZZLE) + { + _SwizzleScanline(pPixels, rowPitch, pPixels, rowPitch, metadata.format, tflags); + } + else + { + _CopyScanline(pPixels, rowPitch, pPixels, rowPitch, metadata.format, tflags); + } + + pPixels += rowPitch; + } + } + + return S_OK; + } } @@ -1331,57 +1353,54 @@ static HRESULT _CopyImageInPlace( DWORD convFlags, _In_ const ScratchImage& imag //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT GetMetadataFromDDSMemory( LPCVOID pSource, size_t size, DWORD flags, TexMetadata& metadata ) +HRESULT DirectX::GetMetadataFromDDSMemory( + const void* pSource, + size_t size, + DWORD flags, + TexMetadata& metadata) { - if ( !pSource || size == 0 ) + if (!pSource || size == 0) return E_INVALIDARG; DWORD convFlags = 0; - return _DecodeDDSHeader( pSource, size, flags, metadata, convFlags ); + return DecodeDDSHeader(pSource, size, flags, metadata, convFlags); } _Use_decl_annotations_ -HRESULT GetMetadataFromDDSFile( LPCWSTR szFile, DWORD flags, TexMetadata& metadata ) +HRESULT DirectX::GetMetadataFromDDSFile( + const wchar_t* szFile, + DWORD flags, + TexMetadata& metadata) { - if ( !szFile ) + if (!szFile) return E_INVALIDARG; #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) - ScopedHandle hFile( safe_handle( CreateFile2( szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, 0 ) ) ); + ScopedHandle hFile(safe_handle(CreateFile2(szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr))); #else - ScopedHandle hFile( safe_handle( CreateFileW( szFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, - FILE_FLAG_SEQUENTIAL_SCAN, 0 ) ) ); + ScopedHandle hFile(safe_handle(CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, nullptr))); #endif - if ( !hFile ) + if (!hFile) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } // Get the file size - LARGE_INTEGER fileSize = {0}; - -#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) FILE_STANDARD_INFO fileInfo; - if ( !GetFileInformationByHandleEx( hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo) ) ) + if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo))) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } - fileSize = fileInfo.EndOfFile; -#else - if ( !GetFileSizeEx( hFile.get(), &fileSize ) ) - { - return HRESULT_FROM_WIN32( GetLastError() ); - } -#endif // File is too big for 32-bit allocation, so reject read (4 GB should be plenty large enough for a valid DDS file) - if ( fileSize.HighPart > 0 ) + if (fileInfo.EndOfFile.HighPart > 0) { - return HRESULT_FROM_WIN32( ERROR_FILE_TOO_LARGE ); + return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE); } // Need at least enough data to fill the standard header and magic number to be a valid DDS - if ( fileSize.LowPart < ( sizeof(DDS_HEADER) + sizeof(uint32_t) ) ) + if (fileInfo.EndOfFile.LowPart < (sizeof(DDS_HEADER) + sizeof(uint32_t))) { return E_FAIL; } @@ -1391,13 +1410,13 @@ HRESULT GetMetadataFromDDSFile( LPCWSTR szFile, DWORD flags, TexMetadata& metada uint8_t header[MAX_HEADER_SIZE]; DWORD bytesRead = 0; - if ( !ReadFile( hFile.get(), header, MAX_HEADER_SIZE, &bytesRead, 0 ) ) + if (!ReadFile(hFile.get(), header, MAX_HEADER_SIZE, &bytesRead, nullptr)) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } DWORD convFlags = 0; - return _DecodeDDSHeader( header, bytesRead, flags, metadata, convFlags ); + return DecodeDDSHeader(header, bytesRead, flags, metadata, convFlags); } @@ -1405,50 +1424,55 @@ HRESULT GetMetadataFromDDSFile( LPCWSTR szFile, DWORD flags, TexMetadata& metada // Load a DDS file in memory //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT LoadFromDDSMemory( LPCVOID pSource, size_t size, DWORD flags, TexMetadata* metadata, ScratchImage& image ) +HRESULT DirectX::LoadFromDDSMemory( + const void* pSource, + size_t size, + DWORD flags, + TexMetadata* metadata, + ScratchImage& image) { - if ( !pSource || size == 0 ) + if (!pSource || size == 0) return E_INVALIDARG; image.Release(); DWORD convFlags = 0; TexMetadata mdata; - HRESULT hr = _DecodeDDSHeader( pSource, size, flags, mdata, convFlags ); - if ( FAILED(hr) ) + HRESULT hr = DecodeDDSHeader(pSource, size, flags, mdata, convFlags); + if (FAILED(hr)) return hr; size_t offset = sizeof(uint32_t) + sizeof(DDS_HEADER); - if ( convFlags & CONV_FLAGS_DX10 ) + if (convFlags & CONV_FLAGS_DX10) offset += sizeof(DDS_HEADER_DXT10); - assert( offset <= size ); + assert(offset <= size); const uint32_t *pal8 = nullptr; - if ( convFlags & CONV_FLAGS_PAL8 ) + if (convFlags & CONV_FLAGS_PAL8) { - pal8 = reinterpret_cast( reinterpret_cast(pSource) + offset ); - assert( pal8 ); - offset += ( 256 * sizeof(uint32_t) ); - if ( size < offset ) + pal8 = reinterpret_cast(reinterpret_cast(pSource) + offset); + assert(pal8); + offset += (256 * sizeof(uint32_t)); + if (size < offset) return E_FAIL; } - hr = image.Initialize( mdata ); - if ( FAILED(hr) ) + hr = image.Initialize(mdata); + if (FAILED(hr)) return hr; - auto pPixels = reinterpret_cast( reinterpret_cast(pSource) + offset ); - assert( pPixels ); - hr = _CopyImage( pPixels, size - offset, mdata, - (flags & DDS_FLAGS_LEGACY_DWORD) ? CP_FLAGS_LEGACY_DWORD : CP_FLAGS_NONE, convFlags, pal8, image ); - if ( FAILED(hr) ) + auto pPixels = reinterpret_cast(reinterpret_cast(pSource) + offset); + assert(pPixels); + hr = CopyImage(pPixels, size - offset, mdata, + (flags & DDS_FLAGS_LEGACY_DWORD) ? CP_FLAGS_LEGACY_DWORD : CP_FLAGS_NONE, convFlags, pal8, image); + if (FAILED(hr)) { image.Release(); return hr; } - if ( metadata ) - memcpy( metadata, &mdata, sizeof(TexMetadata) ); + if (metadata) + memcpy(metadata, &mdata, sizeof(TexMetadata)); return S_OK; } @@ -1458,50 +1482,44 @@ HRESULT LoadFromDDSMemory( LPCVOID pSource, size_t size, DWORD flags, TexMetadat // Load a DDS file from disk //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT LoadFromDDSFile( LPCWSTR szFile, DWORD flags, TexMetadata* metadata, ScratchImage& image ) +HRESULT DirectX::LoadFromDDSFile( + const wchar_t* szFile, + DWORD flags, + TexMetadata* metadata, + ScratchImage& image) { - if ( !szFile ) + if (!szFile) return E_INVALIDARG; image.Release(); #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) - ScopedHandle hFile( safe_handle ( CreateFile2( szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, 0 ) ) ); + ScopedHandle hFile(safe_handle(CreateFile2(szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr))); #else - ScopedHandle hFile( safe_handle ( CreateFileW( szFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, - FILE_FLAG_SEQUENTIAL_SCAN, 0 ) ) ); + ScopedHandle hFile(safe_handle(CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, nullptr))); #endif - if ( !hFile ) + if (!hFile) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } // Get the file size - LARGE_INTEGER fileSize = {0}; - -#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) FILE_STANDARD_INFO fileInfo; - if ( !GetFileInformationByHandleEx( hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo) ) ) + if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo))) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } - fileSize = fileInfo.EndOfFile; -#else - if ( !GetFileSizeEx( hFile.get(), &fileSize ) ) - { - return HRESULT_FROM_WIN32( GetLastError() ); - } -#endif // File is too big for 32-bit allocation, so reject read (4 GB should be plenty large enough for a valid DDS file) - if ( fileSize.HighPart > 0 ) + if (fileInfo.EndOfFile.HighPart > 0) { - return HRESULT_FROM_WIN32( ERROR_FILE_TOO_LARGE ); + return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE); } // Need at least enough data to fill the standard header and magic number to be a valid DDS - if ( fileSize.LowPart < ( sizeof(DDS_HEADER) + sizeof(uint32_t) ) ) + if (fileInfo.EndOfFile.LowPart < (sizeof(DDS_HEADER) + sizeof(uint32_t))) { return E_FAIL; } @@ -1511,86 +1529,86 @@ HRESULT LoadFromDDSFile( LPCWSTR szFile, DWORD flags, TexMetadata* metadata, Scr uint8_t header[MAX_HEADER_SIZE]; DWORD bytesRead = 0; - if ( !ReadFile( hFile.get(), header, MAX_HEADER_SIZE, &bytesRead, 0 ) ) + if (!ReadFile(hFile.get(), header, MAX_HEADER_SIZE, &bytesRead, nullptr)) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } DWORD convFlags = 0; TexMetadata mdata; - HRESULT hr = _DecodeDDSHeader( header, bytesRead, flags, mdata, convFlags ); - if ( FAILED(hr) ) + HRESULT hr = DecodeDDSHeader(header, bytesRead, flags, mdata, convFlags); + if (FAILED(hr)) return hr; DWORD offset = MAX_HEADER_SIZE; - if ( !(convFlags & CONV_FLAGS_DX10) ) + if (!(convFlags & CONV_FLAGS_DX10)) { // Must reset file position since we read more than the standard header above - LARGE_INTEGER filePos = { sizeof(uint32_t) + sizeof(DDS_HEADER), 0}; - if ( !SetFilePointerEx( hFile.get(), filePos, 0, FILE_BEGIN ) ) + LARGE_INTEGER filePos = { sizeof(uint32_t) + sizeof(DDS_HEADER), 0 }; + if (!SetFilePointerEx(hFile.get(), filePos, 0, FILE_BEGIN)) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } offset = sizeof(uint32_t) + sizeof(DDS_HEADER); } std::unique_ptr pal8; - if ( convFlags & CONV_FLAGS_PAL8 ) + if (convFlags & CONV_FLAGS_PAL8) { - pal8.reset( new (std::nothrow) uint32_t[256] ); - if ( !pal8 ) + pal8.reset(new (std::nothrow) uint32_t[256]); + if (!pal8) { return E_OUTOFMEMORY; } - if ( !ReadFile( hFile.get(), pal8.get(), 256 * sizeof(uint32_t), &bytesRead, 0 ) ) + if (!ReadFile(hFile.get(), pal8.get(), 256 * sizeof(uint32_t), &bytesRead, nullptr)) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } - if ( bytesRead != (256 * sizeof(uint32_t)) ) + if (bytesRead != (256 * sizeof(uint32_t))) { return E_FAIL; } - offset += ( 256 * sizeof(uint32_t) ); + offset += (256 * sizeof(uint32_t)); } - DWORD remaining = fileSize.LowPart - offset; - if ( remaining == 0 ) + DWORD remaining = fileInfo.EndOfFile.LowPart - offset; + if (remaining == 0) return E_FAIL; - hr = image.Initialize( mdata ); - if ( FAILED(hr) ) + hr = image.Initialize(mdata); + if (FAILED(hr)) return hr; - if ( (convFlags & CONV_FLAGS_EXPAND) || (flags & DDS_FLAGS_LEGACY_DWORD) ) + if ((convFlags & CONV_FLAGS_EXPAND) || (flags & DDS_FLAGS_LEGACY_DWORD)) { - std::unique_ptr temp( new (std::nothrow) uint8_t[ remaining ] ); - if ( !temp ) + std::unique_ptr temp(new (std::nothrow) uint8_t[remaining]); + if (!temp) { image.Release(); return E_OUTOFMEMORY; } - if ( !ReadFile( hFile.get(), temp.get(), remaining, &bytesRead, 0 ) ) + if (!ReadFile(hFile.get(), temp.get(), remaining, &bytesRead, nullptr)) { image.Release(); - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } - if ( bytesRead != remaining ) + if (bytesRead != remaining) { image.Release(); return E_FAIL; } - hr = _CopyImage( temp.get(), remaining, mdata, - (flags & DDS_FLAGS_LEGACY_DWORD) ? CP_FLAGS_LEGACY_DWORD : CP_FLAGS_NONE, - convFlags, pal8.get(), image ); - if ( FAILED(hr) ) + hr = CopyImage(temp.get(), remaining, mdata, + (flags & DDS_FLAGS_LEGACY_DWORD) ? CP_FLAGS_LEGACY_DWORD : CP_FLAGS_NONE, + convFlags, pal8.get(), image); + if (FAILED(hr)) { image.Release(); return hr; @@ -1598,23 +1616,23 @@ HRESULT LoadFromDDSFile( LPCWSTR szFile, DWORD flags, TexMetadata* metadata, Scr } else { - if ( remaining < image.GetPixelsSize() ) + if (remaining < image.GetPixelsSize()) { image.Release(); return E_FAIL; } - if ( !ReadFile( hFile.get(), image.GetPixels(), static_cast( image.GetPixelsSize() ), &bytesRead, 0 ) ) + if (!ReadFile(hFile.get(), image.GetPixels(), static_cast(image.GetPixelsSize()), &bytesRead, nullptr)) { image.Release(); - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } - if ( convFlags & (CONV_FLAGS_SWIZZLE|CONV_FLAGS_NOALPHA) ) + if (convFlags & (CONV_FLAGS_SWIZZLE | CONV_FLAGS_NOALPHA)) { // Swizzle/copy image in place - hr = _CopyImageInPlace( convFlags, image ); - if ( FAILED(hr) ) + hr = CopyImageInPlace(convFlags, image); + if (FAILED(hr)) { image.Release(); return hr; @@ -1622,8 +1640,8 @@ HRESULT LoadFromDDSFile( LPCWSTR szFile, DWORD flags, TexMetadata* metadata, Scr } } - if ( metadata ) - memcpy( metadata, &mdata, sizeof(TexMetadata) ); + if (metadata) + memcpy(metadata, &mdata, sizeof(TexMetadata)); return S_OK; } @@ -1633,34 +1651,39 @@ HRESULT LoadFromDDSFile( LPCWSTR szFile, DWORD flags, TexMetadata* metadata, Scr // Save a DDS file to memory //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT SaveToDDSMemory( const Image* images, size_t nimages, const TexMetadata& metadata, DWORD flags, Blob& blob ) +HRESULT DirectX::SaveToDDSMemory( + const Image* images, + size_t nimages, + const TexMetadata& metadata, + DWORD flags, + Blob& blob) { - if ( !images || (nimages == 0) ) + if (!images || (nimages == 0)) return E_INVALIDARG; // Determine memory required size_t required = 0; - HRESULT hr = _EncodeDDSHeader( metadata, flags, 0, 0, required ); - if ( FAILED(hr) ) + HRESULT hr = _EncodeDDSHeader(metadata, flags, 0, 0, required); + if (FAILED(hr)) return hr; bool fastpath = true; - for( size_t i = 0; i < nimages; ++i ) + for (size_t i = 0; i < nimages; ++i) { - if ( !images[ i ].pixels ) + if (!images[i].pixels) return E_POINTER; - if ( images[ i ].format != metadata.format ) + if (images[i].format != metadata.format) return E_FAIL; size_t ddsRowPitch, ddsSlicePitch; - ComputePitch( metadata.format, images[ i ].width, images[ i ].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE ); + ComputePitch(metadata.format, images[i].width, images[i].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE); - assert( images[ i ].rowPitch > 0 ); - assert( images[ i ].slicePitch > 0 ); + assert(images[i].rowPitch > 0); + assert(images[i].slicePitch > 0); - if ( ( images[ i ].rowPitch != ddsRowPitch ) || ( images[ i ].slicePitch != ddsSlicePitch ) ) + if ((images[i].rowPitch != ddsRowPitch) || (images[i].slicePitch != ddsSlicePitch)) { fastpath = false; } @@ -1668,19 +1691,19 @@ HRESULT SaveToDDSMemory( const Image* images, size_t nimages, const TexMetadata& required += ddsSlicePitch; } - assert( required > 0 ); + assert(required > 0); blob.Release(); - hr = blob.Initialize( required ); - if ( FAILED(hr) ) + hr = blob.Initialize(required); + if (FAILED(hr)) return hr; - auto pDestination = reinterpret_cast( blob.GetBufferPointer() ); - assert( pDestination ); + auto pDestination = reinterpret_cast(blob.GetBufferPointer()); + assert(pDestination); - hr = _EncodeDDSHeader( metadata, flags, pDestination, blob.GetBufferSize(), required ); - if ( FAILED(hr) ) + hr = _EncodeDDSHeader(metadata, flags, pDestination, blob.GetBufferSize(), required); + if (FAILED(hr)) { blob.Release(); return hr; @@ -1689,147 +1712,147 @@ HRESULT SaveToDDSMemory( const Image* images, size_t nimages, const TexMetadata& size_t remaining = blob.GetBufferSize() - required; pDestination += required; - if ( !remaining ) + if (!remaining) { blob.Release(); return E_FAIL; } - switch( metadata.dimension ) + switch (metadata.dimension) { case DDS_DIMENSION_TEXTURE1D: case DDS_DIMENSION_TEXTURE2D: + { + size_t index = 0; + for (size_t item = 0; item < metadata.arraySize; ++item) { - size_t index = 0; - for( size_t item = 0; item < metadata.arraySize; ++item ) + for (size_t level = 0; level < metadata.mipLevels; ++level) { - for( size_t level = 0; level < metadata.mipLevels; ++level ) + if (index >= nimages) { - if ( index >= nimages ) + blob.Release(); + return E_FAIL; + } + + if (fastpath) + { + size_t pixsize = images[index].slicePitch; + if (memcpy_s(pDestination, remaining, images[index].pixels, pixsize)) { blob.Release(); return E_FAIL; } - if ( fastpath ) + pDestination += pixsize; + remaining -= pixsize; + } + else + { + size_t ddsRowPitch, ddsSlicePitch; + ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE); + + size_t rowPitch = images[index].rowPitch; + + const uint8_t * __restrict sPtr = reinterpret_cast(images[index].pixels); + uint8_t * __restrict dPtr = reinterpret_cast(pDestination); + + size_t lines = ComputeScanlines(metadata.format, images[index].height); + size_t csize = std::min(rowPitch, ddsRowPitch); + size_t tremaining = remaining; + for (size_t j = 0; j < lines; ++j) { - size_t pixsize = images[ index ].slicePitch; - if ( memcpy_s( pDestination, remaining, images[ index ].pixels, pixsize ) ) + if (memcpy_s(dPtr, tremaining, sPtr, csize)) { blob.Release(); return E_FAIL; } - pDestination += pixsize; - remaining -= pixsize; - } - else - { - size_t ddsRowPitch, ddsSlicePitch; - ComputePitch( metadata.format, images[ index ].width, images[ index ].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE ); - - size_t rowPitch = images[ index ].rowPitch; - - const uint8_t * __restrict sPtr = reinterpret_cast(images[ index ].pixels); - uint8_t * __restrict dPtr = reinterpret_cast(pDestination); - - size_t lines = ComputeScanlines( metadata.format, images[ index ].height ); - size_t csize = std::min( rowPitch, ddsRowPitch ); - size_t tremaining = remaining; - for( size_t j = 0; j < lines; ++j ) - { - if ( memcpy_s( dPtr, tremaining, sPtr, csize ) ) - { - blob.Release(); - return E_FAIL; - } - - sPtr += rowPitch; - dPtr += ddsRowPitch; - tremaining -= ddsRowPitch; - } - - pDestination += ddsSlicePitch; - remaining -= ddsSlicePitch; + sPtr += rowPitch; + dPtr += ddsRowPitch; + tremaining -= ddsRowPitch; } - ++index; + pDestination += ddsSlicePitch; + remaining -= ddsSlicePitch; } + + ++index; } } - break; + } + break; case DDS_DIMENSION_TEXTURE3D: + { + if (metadata.arraySize != 1) { - if ( metadata.arraySize != 1 ) - { - blob.Release(); - return E_FAIL; - } + blob.Release(); + return E_FAIL; + } - size_t d = metadata.depth; + size_t d = metadata.depth; - size_t index = 0; - for( size_t level = 0; level < metadata.mipLevels; ++level ) + size_t index = 0; + for (size_t level = 0; level < metadata.mipLevels; ++level) + { + for (size_t slice = 0; slice < d; ++slice) { - for( size_t slice = 0; slice < d; ++slice ) + if (index >= nimages) { - if ( index >= nimages ) + blob.Release(); + return E_FAIL; + } + + if (fastpath) + { + size_t pixsize = images[index].slicePitch; + if (memcpy_s(pDestination, remaining, images[index].pixels, pixsize)) { blob.Release(); return E_FAIL; } - if ( fastpath ) + pDestination += pixsize; + remaining -= pixsize; + } + else + { + size_t ddsRowPitch, ddsSlicePitch; + ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE); + + size_t rowPitch = images[index].rowPitch; + + const uint8_t * __restrict sPtr = reinterpret_cast(images[index].pixels); + uint8_t * __restrict dPtr = reinterpret_cast(pDestination); + + size_t lines = ComputeScanlines(metadata.format, images[index].height); + size_t csize = std::min(rowPitch, ddsRowPitch); + size_t tremaining = remaining; + for (size_t j = 0; j < lines; ++j) { - size_t pixsize = images[ index ].slicePitch; - if ( memcpy_s( pDestination, remaining, images[ index ].pixels, pixsize ) ) + if (memcpy_s(dPtr, tremaining, sPtr, csize)) { blob.Release(); return E_FAIL; } - pDestination += pixsize; - remaining -= pixsize; - } - else - { - size_t ddsRowPitch, ddsSlicePitch; - ComputePitch( metadata.format, images[ index ].width, images[ index ].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE ); - - size_t rowPitch = images[ index ].rowPitch; - - const uint8_t * __restrict sPtr = reinterpret_cast(images[ index ].pixels); - uint8_t * __restrict dPtr = reinterpret_cast(pDestination); - - size_t lines = ComputeScanlines( metadata.format, images[ index ].height ); - size_t csize = std::min( rowPitch, ddsRowPitch ); - size_t tremaining = remaining; - for( size_t j = 0; j < lines; ++j ) - { - if ( memcpy_s( dPtr, tremaining, sPtr, csize ) ) - { - blob.Release(); - return E_FAIL; - } - - sPtr += rowPitch; - dPtr += ddsRowPitch; - tremaining -= ddsRowPitch; - } - - pDestination += ddsSlicePitch; - remaining -= ddsSlicePitch; + sPtr += rowPitch; + dPtr += ddsRowPitch; + tremaining -= ddsRowPitch; } - ++index; + pDestination += ddsSlicePitch; + remaining -= ddsSlicePitch; } - if ( d > 1 ) - d >>= 1; + ++index; } + + if (d > 1) + d >>= 1; } - break; + } + break; default: blob.Release(); @@ -1844,180 +1867,185 @@ HRESULT SaveToDDSMemory( const Image* images, size_t nimages, const TexMetadata& // Save a DDS file to disk //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT SaveToDDSFile( const Image* images, size_t nimages, const TexMetadata& metadata, DWORD flags, LPCWSTR szFile ) +HRESULT DirectX::SaveToDDSFile( + const Image* images, + size_t nimages, + const TexMetadata& metadata, + DWORD flags, + const wchar_t* szFile) { - if ( !szFile ) + if (!szFile) return E_INVALIDARG; // Create DDS Header const size_t MAX_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10); uint8_t header[MAX_HEADER_SIZE]; size_t required; - HRESULT hr = _EncodeDDSHeader( metadata, flags, header, MAX_HEADER_SIZE, required ); - if ( FAILED(hr) ) + HRESULT hr = _EncodeDDSHeader(metadata, flags, header, MAX_HEADER_SIZE, required); + if (FAILED(hr)) return hr; // Create file and write header #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) - ScopedHandle hFile( safe_handle( CreateFile2( szFile, GENERIC_WRITE | DELETE, 0, CREATE_ALWAYS, 0 ) ) ); + ScopedHandle hFile(safe_handle(CreateFile2(szFile, GENERIC_WRITE | DELETE, 0, CREATE_ALWAYS, nullptr))); #else - ScopedHandle hFile( safe_handle( CreateFileW( szFile, GENERIC_WRITE | DELETE, 0, 0, CREATE_ALWAYS, 0, 0 ) ) ); + ScopedHandle hFile(safe_handle(CreateFileW(szFile, GENERIC_WRITE | DELETE, 0, nullptr, CREATE_ALWAYS, 0, nullptr))); #endif - if ( !hFile ) + if (!hFile) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } auto_delete_file delonfail(hFile.get()); DWORD bytesWritten; - if ( !WriteFile( hFile.get(), header, static_cast( required ), &bytesWritten, 0 ) ) + if (!WriteFile(hFile.get(), header, static_cast(required), &bytesWritten, nullptr)) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } - if ( bytesWritten != required ) + if (bytesWritten != required) { return E_FAIL; } // Write images - switch( metadata.dimension ) + switch (metadata.dimension) { case DDS_DIMENSION_TEXTURE1D: case DDS_DIMENSION_TEXTURE2D: + { + size_t index = 0; + for (size_t item = 0; item < metadata.arraySize; ++item) { - size_t index = 0; - for( size_t item = 0; item < metadata.arraySize; ++item ) + for (size_t level = 0; level < metadata.mipLevels; ++level, ++index) { - for( size_t level = 0; level < metadata.mipLevels; ++level, ++index ) + if (index >= nimages) + return E_FAIL; + + if (!images[index].pixels) + return E_POINTER; + + assert(images[index].rowPitch > 0); + assert(images[index].slicePitch > 0); + + size_t ddsRowPitch, ddsSlicePitch; + ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE); + + if (images[index].slicePitch == ddsSlicePitch) { - if ( index >= nimages ) - return E_FAIL; - - if ( !images[ index ].pixels ) - return E_POINTER; - - assert( images[ index ].rowPitch > 0 ); - assert( images[ index ].slicePitch > 0 ); - - size_t ddsRowPitch, ddsSlicePitch; - ComputePitch( metadata.format, images[ index ].width, images[ index ].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE ); - - if ( images[ index ].slicePitch == ddsSlicePitch ) + if (!WriteFile(hFile.get(), images[index].pixels, static_cast(ddsSlicePitch), &bytesWritten, nullptr)) { - if ( !WriteFile( hFile.get(), images[ index ].pixels, static_cast( ddsSlicePitch ), &bytesWritten, 0 ) ) - { - return HRESULT_FROM_WIN32( GetLastError() ); - } - - if ( bytesWritten != ddsSlicePitch ) - { - return E_FAIL; - } + return HRESULT_FROM_WIN32(GetLastError()); } - else + + if (bytesWritten != ddsSlicePitch) { - size_t rowPitch = images[ index ].rowPitch; - if ( rowPitch < ddsRowPitch ) + return E_FAIL; + } + } + else + { + size_t rowPitch = images[index].rowPitch; + if (rowPitch < ddsRowPitch) + { + // DDS uses 1-byte alignment, so if this is happening then the input pitch isn't actually a full line of data + return E_FAIL; + } + + const uint8_t * __restrict sPtr = reinterpret_cast(images[index].pixels); + + size_t lines = ComputeScanlines(metadata.format, images[index].height); + for (size_t j = 0; j < lines; ++j) + { + if (!WriteFile(hFile.get(), sPtr, static_cast(ddsRowPitch), &bytesWritten, nullptr)) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + if (bytesWritten != ddsRowPitch) { - // DDS uses 1-byte alignment, so if this is happening then the input pitch isn't actually a full line of data return E_FAIL; } - const uint8_t * __restrict sPtr = reinterpret_cast(images[ index ].pixels); - - size_t lines = ComputeScanlines( metadata.format, images[ index ].height ); - for( size_t j = 0; j < lines; ++j ) - { - if ( !WriteFile( hFile.get(), sPtr, static_cast( ddsRowPitch ), &bytesWritten, 0 ) ) - { - return HRESULT_FROM_WIN32( GetLastError() ); - } - - if ( bytesWritten != ddsRowPitch ) - { - return E_FAIL; - } - - sPtr += rowPitch; - } + sPtr += rowPitch; } } } } - break; + } + break; case DDS_DIMENSION_TEXTURE3D: + { + if (metadata.arraySize != 1) + return E_FAIL; + + size_t d = metadata.depth; + + size_t index = 0; + for (size_t level = 0; level < metadata.mipLevels; ++level) { - if ( metadata.arraySize != 1 ) - return E_FAIL; - - size_t d = metadata.depth; - - size_t index = 0; - for( size_t level = 0; level < metadata.mipLevels; ++level ) + for (size_t slice = 0; slice < d; ++slice, ++index) { - for( size_t slice = 0; slice < d; ++slice, ++index ) + if (index >= nimages) + return E_FAIL; + + if (!images[index].pixels) + return E_POINTER; + + assert(images[index].rowPitch > 0); + assert(images[index].slicePitch > 0); + + size_t ddsRowPitch, ddsSlicePitch; + ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE); + + if (images[index].slicePitch == ddsSlicePitch) { - if ( index >= nimages ) - return E_FAIL; - - if ( !images[ index ].pixels ) - return E_POINTER; - - assert( images[ index ].rowPitch > 0 ); - assert( images[ index ].slicePitch > 0 ); - - size_t ddsRowPitch, ddsSlicePitch; - ComputePitch( metadata.format, images[ index ].width, images[ index ].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE ); - - if ( images[ index ].slicePitch == ddsSlicePitch ) + if (!WriteFile(hFile.get(), images[index].pixels, static_cast(ddsSlicePitch), &bytesWritten, nullptr)) { - if ( !WriteFile( hFile.get(), images[ index ].pixels, static_cast( ddsSlicePitch ), &bytesWritten, 0 ) ) - { - return HRESULT_FROM_WIN32( GetLastError() ); - } - - if ( bytesWritten != ddsSlicePitch ) - { - return E_FAIL; - } + return HRESULT_FROM_WIN32(GetLastError()); } - else + + if (bytesWritten != ddsSlicePitch) { - size_t rowPitch = images[ index ].rowPitch; - if ( rowPitch < ddsRowPitch ) - { - // DDS uses 1-byte alignment, so if this is happening then the input pitch isn't actually a full line of data - return E_FAIL; - } - - const uint8_t * __restrict sPtr = reinterpret_cast(images[ index ].pixels); - - size_t lines = ComputeScanlines( metadata.format, images[ index ].height ); - for( size_t j = 0; j < lines; ++j ) - { - if ( !WriteFile( hFile.get(), sPtr, static_cast( ddsRowPitch ), &bytesWritten, 0 ) ) - { - return HRESULT_FROM_WIN32( GetLastError() ); - } - - if ( bytesWritten != ddsRowPitch ) - { - return E_FAIL; - } - - sPtr += rowPitch; - } + return E_FAIL; } } + else + { + size_t rowPitch = images[index].rowPitch; + if (rowPitch < ddsRowPitch) + { + // DDS uses 1-byte alignment, so if this is happening then the input pitch isn't actually a full line of data + return E_FAIL; + } - if ( d > 1 ) - d >>= 1; + const uint8_t * __restrict sPtr = reinterpret_cast(images[index].pixels); + + size_t lines = ComputeScanlines(metadata.format, images[index].height); + for (size_t j = 0; j < lines; ++j) + { + if (!WriteFile(hFile.get(), sPtr, static_cast(ddsRowPitch), &bytesWritten, nullptr)) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + if (bytesWritten != ddsRowPitch) + { + return E_FAIL; + } + + sPtr += rowPitch; + } + } } + + if (d > 1) + d >>= 1; } - break; + } + break; default: return E_FAIL; @@ -2027,5 +2055,3 @@ HRESULT SaveToDDSFile( const Image* images, size_t nimages, const TexMetadata& m return S_OK; } - -}; // namespace diff --git a/DirectXTex/DirectXTexFlipRotate.cpp b/DirectXTex/DirectXTexFlipRotate.cpp index 671137a..9036282 100644 --- a/DirectXTex/DirectXTexFlipRotate.cpp +++ b/DirectXTex/DirectXTexFlipRotate.cpp @@ -15,110 +15,117 @@ #include "directxtexp.h" +using namespace DirectX; using Microsoft::WRL::ComPtr; -namespace DirectX +namespace { - -//------------------------------------------------------------------------------------- -// Do flip/rotate operation using WIC -//------------------------------------------------------------------------------------- -static HRESULT _PerformFlipRotateUsingWIC( _In_ const Image& srcImage, _In_ DWORD flags, - _In_ const WICPixelFormatGUID& pfGUID, _In_ const Image& destImage ) -{ - if ( !srcImage.pixels || !destImage.pixels ) - return E_POINTER; - - assert( srcImage.format == destImage.format ); - - bool iswic2 = false; - IWICImagingFactory* pWIC = GetWICFactory(iswic2); - if ( !pWIC ) - return E_NOINTERFACE; - - ComPtr source; - HRESULT hr = pWIC->CreateBitmapFromMemory( static_cast( srcImage.width ), static_cast( srcImage.height ), pfGUID, - static_cast( srcImage.rowPitch ), static_cast( srcImage.slicePitch ), - srcImage.pixels, source.GetAddressOf() ); - if ( FAILED(hr) ) - return hr; - - ComPtr FR; - hr = pWIC->CreateBitmapFlipRotator( FR.GetAddressOf() ); - if ( FAILED(hr) ) - return hr; - - hr = FR->Initialize( source.Get(), static_cast( flags ) ); - if ( FAILED(hr) ) - return hr; - - WICPixelFormatGUID pfFR; - hr = FR->GetPixelFormat( &pfFR ); - if ( FAILED(hr) ) - return hr; - - if ( memcmp( &pfFR, &pfGUID, sizeof(GUID) ) != 0 ) + //------------------------------------------------------------------------------------- + // Do flip/rotate operation using WIC + //------------------------------------------------------------------------------------- + HRESULT PerformFlipRotateUsingWIC( + const Image& srcImage, + DWORD flags, + const WICPixelFormatGUID& pfGUID, + const Image& destImage) { - // Flip/rotate should return the same format as the source... - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if (!srcImage.pixels || !destImage.pixels) + return E_POINTER; + + assert(srcImage.format == destImage.format); + + bool iswic2 = false; + IWICImagingFactory* pWIC = GetWICFactory(iswic2); + if (!pWIC) + return E_NOINTERFACE; + + ComPtr source; + HRESULT hr = pWIC->CreateBitmapFromMemory(static_cast(srcImage.width), static_cast(srcImage.height), pfGUID, + static_cast(srcImage.rowPitch), static_cast(srcImage.slicePitch), + srcImage.pixels, source.GetAddressOf()); + if (FAILED(hr)) + return hr; + + ComPtr FR; + hr = pWIC->CreateBitmapFlipRotator(FR.GetAddressOf()); + if (FAILED(hr)) + return hr; + + hr = FR->Initialize(source.Get(), static_cast(flags)); + if (FAILED(hr)) + return hr; + + WICPixelFormatGUID pfFR; + hr = FR->GetPixelFormat(&pfFR); + if (FAILED(hr)) + return hr; + + if (memcmp(&pfFR, &pfGUID, sizeof(GUID)) != 0) + { + // Flip/rotate should return the same format as the source... + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + UINT nwidth, nheight; + hr = FR->GetSize(&nwidth, &nheight); + if (FAILED(hr)) + return hr; + + if (destImage.width != nwidth || destImage.height != nheight) + return E_FAIL; + + hr = FR->CopyPixels(0, static_cast(destImage.rowPitch), static_cast(destImage.slicePitch), destImage.pixels); + if (FAILED(hr)) + return hr; + + return S_OK; } - UINT nwidth, nheight; - hr = FR->GetSize( &nwidth, &nheight ); - if ( FAILED(hr) ) - return hr; - if ( destImage.width != nwidth || destImage.height != nheight ) - return E_FAIL; + //------------------------------------------------------------------------------------- + // Do conversion, flip/rotate using WIC, conversion cycle + //------------------------------------------------------------------------------------- + HRESULT PerformFlipRotateViaF32( + const Image& srcImage, + DWORD flags, + const Image& destImage) + { + if (!srcImage.pixels || !destImage.pixels) + return E_POINTER; - hr = FR->CopyPixels( 0, static_cast( destImage.rowPitch ), static_cast( destImage.slicePitch ), destImage.pixels ); - if ( FAILED(hr) ) - return hr; + assert(srcImage.format != DXGI_FORMAT_R32G32B32A32_FLOAT); + assert(srcImage.format == destImage.format); - return S_OK; -} + ScratchImage temp; + HRESULT hr = _ConvertToR32G32B32A32(srcImage, temp); + if (FAILED(hr)) + return hr; + const Image *tsrc = temp.GetImage(0, 0, 0); + if (!tsrc) + return E_POINTER; -//------------------------------------------------------------------------------------- -// Do conversion, flip/rotate using WIC, conversion cycle -//------------------------------------------------------------------------------------- -static HRESULT _PerformFlipRotateViaF32( _In_ const Image& srcImage, _In_ DWORD flags, _In_ const Image& destImage ) -{ - if ( !srcImage.pixels || !destImage.pixels ) - return E_POINTER; + ScratchImage rtemp; + hr = rtemp.Initialize2D(DXGI_FORMAT_R32G32B32A32_FLOAT, destImage.width, destImage.height, 1, 1); + if (FAILED(hr)) + return hr; - assert( srcImage.format != DXGI_FORMAT_R32G32B32A32_FLOAT ); - assert( srcImage.format == destImage.format ); + const Image *tdest = rtemp.GetImage(0, 0, 0); + if (!tdest) + return E_POINTER; - ScratchImage temp; - HRESULT hr = _ConvertToR32G32B32A32( srcImage, temp ); - if ( FAILED(hr) ) - return hr; + hr = PerformFlipRotateUsingWIC(*tsrc, flags, GUID_WICPixelFormat128bppRGBAFloat, *tdest); + if (FAILED(hr)) + return hr; - const Image *tsrc = temp.GetImage( 0, 0, 0 ); - if ( !tsrc ) - return E_POINTER; + temp.Release(); - ScratchImage rtemp; - hr = rtemp.Initialize2D( DXGI_FORMAT_R32G32B32A32_FLOAT, destImage.width, destImage.height, 1, 1 ); - if ( FAILED(hr) ) - return hr; + hr = _ConvertFromR32G32B32A32(*tdest, destImage); + if (FAILED(hr)) + return hr; - const Image *tdest = rtemp.GetImage( 0, 0, 0 ); - if ( !tdest ) - return E_POINTER; - - hr = _PerformFlipRotateUsingWIC( *tsrc, flags, GUID_WICPixelFormat128bppRGBAFloat, *tdest ); - if ( FAILED(hr) ) - return hr; - - temp.Release(); - - hr = _ConvertFromR32G32B32A32( *tdest, destImage ); - if ( FAILED(hr) ) - return hr; - - return S_OK; + return S_OK; + } } @@ -130,32 +137,35 @@ static HRESULT _PerformFlipRotateViaF32( _In_ const Image& srcImage, _In_ DWORD // Flip/rotate image //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT FlipRotate( const Image& srcImage, DWORD flags, ScratchImage& image ) +HRESULT DirectX::FlipRotate( + const Image& srcImage, + DWORD flags, + ScratchImage& image) { - if ( !srcImage.pixels ) + if (!srcImage.pixels) return E_POINTER; - if ( !flags ) + if (!flags) return E_INVALIDARG; - if ( (srcImage.width > UINT32_MAX) || (srcImage.height > UINT32_MAX) ) + if ((srcImage.width > UINT32_MAX) || (srcImage.height > UINT32_MAX)) return E_INVALIDARG; - if ( IsCompressed( srcImage.format ) ) + if (IsCompressed(srcImage.format)) { // We don't support flip/rotate operations on compressed images - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } - static_assert( TEX_FR_ROTATE0 == WICBitmapTransformRotate0, "TEX_FR_ROTATE0 no longer matches WIC" ); - static_assert( TEX_FR_ROTATE90 == WICBitmapTransformRotate90, "TEX_FR_ROTATE90 no longer matches WIC" ); - static_assert( TEX_FR_ROTATE180 == WICBitmapTransformRotate180, "TEX_FR_ROTATE180 no longer matches WIC" ); - static_assert( TEX_FR_ROTATE270 == WICBitmapTransformRotate270, "TEX_FR_ROTATE270 no longer matches WIC" ); - static_assert( TEX_FR_FLIP_HORIZONTAL == WICBitmapTransformFlipHorizontal, "TEX_FR_FLIP_HORIZONTAL no longer matches WIC" ); - static_assert( TEX_FR_FLIP_VERTICAL == WICBitmapTransformFlipVertical, "TEX_FR_FLIP_VERTICAL no longer matches WIC" ); + static_assert(TEX_FR_ROTATE0 == WICBitmapTransformRotate0, "TEX_FR_ROTATE0 no longer matches WIC"); + static_assert(TEX_FR_ROTATE90 == WICBitmapTransformRotate90, "TEX_FR_ROTATE90 no longer matches WIC"); + static_assert(TEX_FR_ROTATE180 == WICBitmapTransformRotate180, "TEX_FR_ROTATE180 no longer matches WIC"); + static_assert(TEX_FR_ROTATE270 == WICBitmapTransformRotate270, "TEX_FR_ROTATE270 no longer matches WIC"); + static_assert(TEX_FR_FLIP_HORIZONTAL == WICBitmapTransformFlipHorizontal, "TEX_FR_FLIP_HORIZONTAL no longer matches WIC"); + static_assert(TEX_FR_FLIP_VERTICAL == WICBitmapTransformFlipVertical, "TEX_FR_FLIP_VERTICAL no longer matches WIC"); // Only supports 90, 180, 270, or no rotation flags... not a combination of rotation flags - switch ( flags & (TEX_FR_ROTATE90|TEX_FR_ROTATE180|TEX_FR_ROTATE270) ) + switch (flags & (TEX_FR_ROTATE90 | TEX_FR_ROTATE180 | TEX_FR_ROTATE270)) { case 0: case TEX_FR_ROTATE90: @@ -170,33 +180,33 @@ HRESULT FlipRotate( const Image& srcImage, DWORD flags, ScratchImage& image ) size_t nwidth = srcImage.width; size_t nheight = srcImage.height; - if (flags & (TEX_FR_ROTATE90|TEX_FR_ROTATE270)) + if (flags & (TEX_FR_ROTATE90 | TEX_FR_ROTATE270)) { nwidth = srcImage.height; nheight = srcImage.width; } - HRESULT hr = image.Initialize2D( srcImage.format, nwidth, nheight, 1, 1 ); - if ( FAILED(hr) ) + HRESULT hr = image.Initialize2D(srcImage.format, nwidth, nheight, 1, 1); + if (FAILED(hr)) return hr; - - const Image *rimage = image.GetImage( 0, 0, 0 ); - if ( !rimage ) + + const Image *rimage = image.GetImage(0, 0, 0); + if (!rimage) return E_POINTER; WICPixelFormatGUID pfGUID; - if ( _DXGIToWIC( srcImage.format, pfGUID ) ) + if (_DXGIToWIC(srcImage.format, pfGUID)) { // Case 1: Source format is supported by Windows Imaging Component - hr = _PerformFlipRotateUsingWIC( srcImage, flags, pfGUID, *rimage ); + hr = PerformFlipRotateUsingWIC(srcImage, flags, pfGUID, *rimage); } else { // Case 2: Source format is not supported by WIC, so we have to convert, flip/rotate, and convert back - hr = _PerformFlipRotateViaF32( srcImage, flags, *rimage ); + hr = PerformFlipRotateViaF32(srcImage, flags, *rimage); } - if ( FAILED(hr) ) + if (FAILED(hr)) { image.Release(); return hr; @@ -210,27 +220,31 @@ HRESULT FlipRotate( const Image& srcImage, DWORD flags, ScratchImage& image ) // Flip/rotate image (complex) //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT FlipRotate( const Image* srcImages, size_t nimages, const TexMetadata& metadata, - DWORD flags, ScratchImage& result ) +HRESULT DirectX::FlipRotate( + const Image* srcImages, + size_t nimages, + const TexMetadata& metadata, + DWORD flags, + ScratchImage& result) { - if ( !srcImages || !nimages ) + if (!srcImages || !nimages) return E_INVALIDARG; - if ( IsCompressed( metadata.format ) ) + if (IsCompressed(metadata.format)) { // We don't support flip/rotate operations on compressed images - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } - static_assert( TEX_FR_ROTATE0 == WICBitmapTransformRotate0, "TEX_FR_ROTATE0 no longer matches WIC" ); - static_assert( TEX_FR_ROTATE90 == WICBitmapTransformRotate90, "TEX_FR_ROTATE90 no longer matches WIC" ); - static_assert( TEX_FR_ROTATE180 == WICBitmapTransformRotate180, "TEX_FR_ROTATE180 no longer matches WIC" ); - static_assert( TEX_FR_ROTATE270 == WICBitmapTransformRotate270, "TEX_FR_ROTATE270 no longer matches WIC" ); - static_assert( TEX_FR_FLIP_HORIZONTAL == WICBitmapTransformFlipHorizontal, "TEX_FR_FLIP_HORIZONTAL no longer matches WIC" ); - static_assert( TEX_FR_FLIP_VERTICAL == WICBitmapTransformFlipVertical, "TEX_FR_FLIP_VERTICAL no longer matches WIC" ); + static_assert(TEX_FR_ROTATE0 == WICBitmapTransformRotate0, "TEX_FR_ROTATE0 no longer matches WIC"); + static_assert(TEX_FR_ROTATE90 == WICBitmapTransformRotate90, "TEX_FR_ROTATE90 no longer matches WIC"); + static_assert(TEX_FR_ROTATE180 == WICBitmapTransformRotate180, "TEX_FR_ROTATE180 no longer matches WIC"); + static_assert(TEX_FR_ROTATE270 == WICBitmapTransformRotate270, "TEX_FR_ROTATE270 no longer matches WIC"); + static_assert(TEX_FR_FLIP_HORIZONTAL == WICBitmapTransformFlipHorizontal, "TEX_FR_FLIP_HORIZONTAL no longer matches WIC"); + static_assert(TEX_FR_FLIP_VERTICAL == WICBitmapTransformFlipVertical, "TEX_FR_FLIP_VERTICAL no longer matches WIC"); // Only supports 90, 180, 270, or no rotation flags... not a combination of rotation flags - switch ( flags & (TEX_FR_ROTATE90|TEX_FR_ROTATE180|TEX_FR_ROTATE270) ) + switch (flags & (TEX_FR_ROTATE90 | TEX_FR_ROTATE180 | TEX_FR_ROTATE270)) { case 0: case TEX_FR_ROTATE90: @@ -245,51 +259,51 @@ HRESULT FlipRotate( const Image* srcImages, size_t nimages, const TexMetadata& m TexMetadata mdata2 = metadata; bool flipwh = false; - if (flags & (TEX_FR_ROTATE90|TEX_FR_ROTATE270)) + if (flags & (TEX_FR_ROTATE90 | TEX_FR_ROTATE270)) { flipwh = true; mdata2.width = metadata.height; mdata2.height = metadata.width; } - HRESULT hr = result.Initialize( mdata2 ); - if ( FAILED(hr) ) + HRESULT hr = result.Initialize(mdata2); + if (FAILED(hr)) return hr; - if ( nimages != result.GetImageCount() ) + if (nimages != result.GetImageCount()) { result.Release(); return E_FAIL; } const Image* dest = result.GetImages(); - if ( !dest ) + if (!dest) { result.Release(); return E_POINTER; } WICPixelFormatGUID pfGUID; - bool wicpf = _DXGIToWIC( metadata.format, pfGUID ); + bool wicpf = _DXGIToWIC(metadata.format, pfGUID); - for( size_t index=0; index < nimages; ++index ) + for (size_t index = 0; index < nimages; ++index) { - const Image& src = srcImages[ index ]; - if ( src.format != metadata.format ) + const Image& src = srcImages[index]; + if (src.format != metadata.format) { result.Release(); return E_FAIL; } - if ( (src.width > UINT32_MAX) || (src.height > UINT32_MAX) ) + if ((src.width > UINT32_MAX) || (src.height > UINT32_MAX)) return E_FAIL; - const Image& dst = dest[ index ]; - assert( dst.format == metadata.format ); + const Image& dst = dest[index]; + assert(dst.format == metadata.format); - if ( flipwh ) + if (flipwh) { - if ( src.width != dst.height || src.height != dst.width ) + if (src.width != dst.height || src.height != dst.width) { result.Release(); return E_FAIL; @@ -297,7 +311,7 @@ HRESULT FlipRotate( const Image* srcImages, size_t nimages, const TexMetadata& m } else { - if ( src.width != dst.width || src.height != dst.height ) + if (src.width != dst.width || src.height != dst.height) { result.Release(); return E_FAIL; @@ -307,15 +321,15 @@ HRESULT FlipRotate( const Image* srcImages, size_t nimages, const TexMetadata& m if (wicpf) { // Case 1: Source format is supported by Windows Imaging Component - hr = _PerformFlipRotateUsingWIC( src, flags, pfGUID, dst ); + hr = PerformFlipRotateUsingWIC(src, flags, pfGUID, dst); } else { // Case 2: Source format is not supported by WIC, so we have to convert, flip/rotate, and convert back - hr = _PerformFlipRotateViaF32( src, flags, dst ); + hr = PerformFlipRotateViaF32(src, flags, dst); } - if ( FAILED(hr) ) + if (FAILED(hr)) { result.Release(); return hr; @@ -324,5 +338,3 @@ HRESULT FlipRotate( const Image* srcImages, size_t nimages, const TexMetadata& m return S_OK; } - -}; // namespace diff --git a/DirectXTex/DirectXTexImage.cpp b/DirectXTex/DirectXTexImage.cpp index 635d707..1bbbb20 100644 --- a/DirectXTex/DirectXTexImage.cpp +++ b/DirectXTex/DirectXTexImage.cpp @@ -17,82 +17,87 @@ namespace DirectX { + extern bool _CalculateMipLevels(_In_ size_t width, _In_ size_t height, _Inout_ size_t& mipLevels); + extern bool _CalculateMipLevels3D(_In_ size_t width, _In_ size_t height, _In_ size_t depth, _Inout_ size_t& mipLevels); + extern bool _IsAlphaAllOpaqueBC(_In_ const Image& cImage); +} -extern bool _CalculateMipLevels( _In_ size_t width, _In_ size_t height, _Inout_ size_t& mipLevels ); -extern bool _CalculateMipLevels3D( _In_ size_t width, _In_ size_t height, _In_ size_t depth, _Inout_ size_t& mipLevels ); -extern bool _IsAlphaAllOpaqueBC( _In_ const Image& cImage ); +using namespace DirectX; //------------------------------------------------------------------------------------- // Determines number of image array entries and pixel size //------------------------------------------------------------------------------------- _Use_decl_annotations_ -void _DetermineImageArray( const TexMetadata& metadata, DWORD cpFlags, - size_t& nImages, size_t& pixelSize ) +void DirectX::_DetermineImageArray( + const TexMetadata& metadata, + DWORD cpFlags, + size_t& nImages, + size_t& pixelSize) { - assert( metadata.width > 0 && metadata.height > 0 && metadata.depth > 0 ); - assert( metadata.arraySize > 0 ); - assert( metadata.mipLevels > 0 ); + assert(metadata.width > 0 && metadata.height > 0 && metadata.depth > 0); + assert(metadata.arraySize > 0); + assert(metadata.mipLevels > 0); size_t _pixelSize = 0; size_t _nimages = 0; - switch( metadata.dimension ) + switch (metadata.dimension) { case TEX_DIMENSION_TEXTURE1D: case TEX_DIMENSION_TEXTURE2D: - for( size_t item = 0; item < metadata.arraySize; ++item ) + for (size_t item = 0; item < metadata.arraySize; ++item) { size_t w = metadata.width; size_t h = metadata.height; - for( size_t level=0; level < metadata.mipLevels; ++level ) + for (size_t level = 0; level < metadata.mipLevels; ++level) { size_t rowPitch, slicePitch; - ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags ); + ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags); _pixelSize += slicePitch; ++_nimages; - if ( h > 1 ) + if (h > 1) h >>= 1; - if ( w > 1 ) + if (w > 1) w >>= 1; } } break; case TEX_DIMENSION_TEXTURE3D: + { + size_t w = metadata.width; + size_t h = metadata.height; + size_t d = metadata.depth; + + for (size_t level = 0; level < metadata.mipLevels; ++level) { - size_t w = metadata.width; - size_t h = metadata.height; - size_t d = metadata.depth; + size_t rowPitch, slicePitch; + ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags); - for( size_t level=0; level < metadata.mipLevels; ++level ) + for (size_t slice = 0; slice < d; ++slice) { - size_t rowPitch, slicePitch; - ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags ); - - for( size_t slice=0; slice < d; ++slice ) - { - _pixelSize += slicePitch; - ++_nimages; - } - - if ( h > 1 ) - h >>= 1; - - if ( w > 1 ) - w >>= 1; - - if ( d > 1 ) - d >>= 1; + _pixelSize += slicePitch; + ++_nimages; } + + if (h > 1) + h >>= 1; + + if (w > 1) + w >>= 1; + + if (d > 1) + d >>= 1; } - break; + } + break; default: - assert( false ); + assert(false); break; } @@ -105,22 +110,26 @@ void _DetermineImageArray( const TexMetadata& metadata, DWORD cpFlags, // Fills in the image array entries //------------------------------------------------------------------------------------- _Use_decl_annotations_ -bool _SetupImageArray( uint8_t *pMemory, size_t pixelSize, - const TexMetadata& metadata, DWORD cpFlags, - Image* images, size_t nImages ) +bool DirectX::_SetupImageArray( + uint8_t *pMemory, + size_t pixelSize, + const TexMetadata& metadata, + DWORD cpFlags, + Image* images, + size_t nImages) { - assert( pMemory ); - assert( pixelSize > 0 ); - assert( nImages > 0 ); + assert(pMemory); + assert(pixelSize > 0); + assert(nImages > 0); - if ( !images ) + if (!images) return false; size_t index = 0; uint8_t* pixels = pMemory; const uint8_t* pEndBits = pMemory + pixelSize; - switch( metadata.dimension ) + switch (metadata.dimension) { case TEX_DIMENSION_TEXTURE1D: case TEX_DIMENSION_TEXTURE2D: @@ -129,20 +138,20 @@ bool _SetupImageArray( uint8_t *pMemory, size_t pixelSize, return false; } - for( size_t item = 0; item < metadata.arraySize; ++item ) + for (size_t item = 0; item < metadata.arraySize; ++item) { size_t w = metadata.width; size_t h = metadata.height; - for( size_t level=0; level < metadata.mipLevels; ++level ) + for (size_t level = 0; level < metadata.mipLevels; ++level) { - if ( index >= nImages ) + if (index >= nImages) { return false; } size_t rowPitch, slicePitch; - ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags ); + ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags); images[index].width = w; images[index].height = h; @@ -153,71 +162,71 @@ bool _SetupImageArray( uint8_t *pMemory, size_t pixelSize, ++index; pixels += slicePitch; - if ( pixels > pEndBits ) + if (pixels > pEndBits) { return false; } - - if ( h > 1 ) + + if (h > 1) h >>= 1; - if ( w > 1 ) + if (w > 1) w >>= 1; } } return true; case TEX_DIMENSION_TEXTURE3D: + { + if (metadata.mipLevels == 0 || metadata.depth == 0) { - if (metadata.mipLevels == 0 || metadata.depth == 0) - { - return false; - } - - size_t w = metadata.width; - size_t h = metadata.height; - size_t d = metadata.depth; - - for( size_t level=0; level < metadata.mipLevels; ++level ) - { - size_t rowPitch, slicePitch; - ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags ); - - for( size_t slice=0; slice < d; ++slice ) - { - if ( index >= nImages ) - { - return false; - } - - // We use the same memory organization that Direct3D 11 needs for D3D11_SUBRESOURCE_DATA - // with all slices of a given miplevel being continuous in memory - images[index].width = w; - images[index].height = h; - images[index].format = metadata.format; - images[index].rowPitch = rowPitch; - images[index].slicePitch = slicePitch; - images[index].pixels = pixels; - ++index; - - pixels += slicePitch; - if ( pixels > pEndBits ) - { - return false; - } - } - - if ( h > 1 ) - h >>= 1; - - if ( w > 1 ) - w >>= 1; - - if ( d > 1 ) - d >>= 1; - } + return false; } - return true; + + size_t w = metadata.width; + size_t h = metadata.height; + size_t d = metadata.depth; + + for (size_t level = 0; level < metadata.mipLevels; ++level) + { + size_t rowPitch, slicePitch; + ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags); + + for (size_t slice = 0; slice < d; ++slice) + { + if (index >= nImages) + { + return false; + } + + // We use the same memory organization that Direct3D 11 needs for D3D11_SUBRESOURCE_DATA + // with all slices of a given miplevel being continuous in memory + images[index].width = w; + images[index].height = h; + images[index].format = metadata.format; + images[index].rowPitch = rowPitch; + images[index].slicePitch = slicePitch; + images[index].pixels = pixels; + ++index; + + pixels += slicePitch; + if (pixels > pEndBits) + { + return false; + } + } + + if (h > 1) + h >>= 1; + + if (w > 1) + w >>= 1; + + if (d > 1) + d >>= 1; + } + } + return true; default: return false; @@ -231,20 +240,20 @@ bool _SetupImageArray( uint8_t *pMemory, size_t pixelSize, ScratchImage& ScratchImage::operator= (ScratchImage&& moveFrom) { - if ( this != &moveFrom ) + if (this != &moveFrom) { Release(); - _nimages = moveFrom._nimages; - _size = moveFrom._size; - _metadata = moveFrom._metadata; - _image = moveFrom._image; - _memory = moveFrom._memory; + m_nimages = moveFrom.m_nimages; + m_size = moveFrom.m_size; + m_metadata = moveFrom.m_metadata; + m_image = moveFrom.m_image; + m_memory = moveFrom.m_memory; - moveFrom._nimages = 0; - moveFrom._size = 0; - moveFrom._image = nullptr; - moveFrom._memory = nullptr; + moveFrom.m_nimages = 0; + moveFrom.m_size = 0; + moveFrom.m_image = nullptr; + moveFrom.m_memory = nullptr; } return *this; } @@ -254,82 +263,82 @@ ScratchImage& ScratchImage::operator= (ScratchImage&& moveFrom) // Methods //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT ScratchImage::Initialize( const TexMetadata& mdata, DWORD flags ) +HRESULT ScratchImage::Initialize(const TexMetadata& mdata, DWORD flags) { - if ( !IsValid(mdata.format) ) + if (!IsValid(mdata.format)) return E_INVALIDARG; - if ( IsPalettized(mdata.format) ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if (IsPalettized(mdata.format)) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); size_t mipLevels = mdata.mipLevels; - switch( mdata.dimension ) + switch (mdata.dimension) { case TEX_DIMENSION_TEXTURE1D: - if ( !mdata.width || mdata.height != 1 || mdata.depth != 1 || !mdata.arraySize ) + if (!mdata.width || mdata.height != 1 || mdata.depth != 1 || !mdata.arraySize) return E_INVALIDARG; - if ( !_CalculateMipLevels(mdata.width,1,mipLevels) ) + if (!_CalculateMipLevels(mdata.width, 1, mipLevels)) return E_INVALIDARG; break; case TEX_DIMENSION_TEXTURE2D: - if ( !mdata.width || !mdata.height || mdata.depth != 1 || !mdata.arraySize ) + if (!mdata.width || !mdata.height || mdata.depth != 1 || !mdata.arraySize) return E_INVALIDARG; - if ( mdata.IsCubemap() ) + if (mdata.IsCubemap()) { - if ( (mdata.arraySize % 6) != 0 ) + if ((mdata.arraySize % 6) != 0) return E_INVALIDARG; } - if ( !_CalculateMipLevels(mdata.width,mdata.height,mipLevels) ) + if (!_CalculateMipLevels(mdata.width, mdata.height, mipLevels)) return E_INVALIDARG; break; case TEX_DIMENSION_TEXTURE3D: - if ( !mdata.width || !mdata.height || !mdata.depth || mdata.arraySize != 1 ) + if (!mdata.width || !mdata.height || !mdata.depth || mdata.arraySize != 1) return E_INVALIDARG; - - if ( !_CalculateMipLevels3D(mdata.width,mdata.height,mdata.depth,mipLevels) ) + + if (!_CalculateMipLevels3D(mdata.width, mdata.height, mdata.depth, mipLevels)) return E_INVALIDARG; break; default: - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } Release(); - _metadata.width = mdata.width; - _metadata.height = mdata.height; - _metadata.depth = mdata.depth; - _metadata.arraySize = mdata.arraySize; - _metadata.mipLevels = mipLevels; - _metadata.miscFlags = mdata.miscFlags; - _metadata.miscFlags2 = mdata.miscFlags2; - _metadata.format = mdata.format; - _metadata.dimension = mdata.dimension; + m_metadata.width = mdata.width; + m_metadata.height = mdata.height; + m_metadata.depth = mdata.depth; + m_metadata.arraySize = mdata.arraySize; + m_metadata.mipLevels = mipLevels; + m_metadata.miscFlags = mdata.miscFlags; + m_metadata.miscFlags2 = mdata.miscFlags2; + m_metadata.format = mdata.format; + m_metadata.dimension = mdata.dimension; size_t pixelSize, nimages; - _DetermineImageArray( _metadata, flags, nimages, pixelSize ); + _DetermineImageArray(m_metadata, flags, nimages, pixelSize); - _image = new (std::nothrow) Image[ nimages ]; - if ( !_image ) + m_image = new (std::nothrow) Image[nimages]; + if (!m_image) return E_OUTOFMEMORY; - _nimages = nimages; - memset( _image, 0, sizeof(Image) * nimages ); + m_nimages = nimages; + memset(m_image, 0, sizeof(Image) * nimages); - _memory = reinterpret_cast( _aligned_malloc( pixelSize, 16 ) ); - if ( !_memory ) + m_memory = reinterpret_cast(_aligned_malloc(pixelSize, 16)); + if (!m_memory) { Release(); return E_OUTOFMEMORY; } - _size = pixelSize; - if ( !_SetupImageArray( _memory, pixelSize, _metadata, flags, _image, nimages ) ) + m_size = pixelSize; + if (!_SetupImageArray(m_memory, pixelSize, m_metadata, flags, m_image, nimages)) { Release(); return E_FAIL; @@ -339,63 +348,63 @@ HRESULT ScratchImage::Initialize( const TexMetadata& mdata, DWORD flags ) } _Use_decl_annotations_ -HRESULT ScratchImage::Initialize1D( DXGI_FORMAT fmt, size_t length, size_t arraySize, size_t mipLevels, DWORD flags ) +HRESULT ScratchImage::Initialize1D(DXGI_FORMAT fmt, size_t length, size_t arraySize, size_t mipLevels, DWORD flags) { - if ( !length || !arraySize ) + if (!length || !arraySize) return E_INVALIDARG; // 1D is a special case of the 2D case - HRESULT hr = Initialize2D( fmt, length, 1, arraySize, mipLevels, flags ); - if ( FAILED(hr) ) + HRESULT hr = Initialize2D(fmt, length, 1, arraySize, mipLevels, flags); + if (FAILED(hr)) return hr; - _metadata.dimension = TEX_DIMENSION_TEXTURE1D; + m_metadata.dimension = TEX_DIMENSION_TEXTURE1D; return S_OK; } _Use_decl_annotations_ -HRESULT ScratchImage::Initialize2D( DXGI_FORMAT fmt, size_t width, size_t height, size_t arraySize, size_t mipLevels, DWORD flags ) +HRESULT ScratchImage::Initialize2D(DXGI_FORMAT fmt, size_t width, size_t height, size_t arraySize, size_t mipLevels, DWORD flags) { - if ( !IsValid(fmt) || !width || !height || !arraySize ) + if (!IsValid(fmt) || !width || !height || !arraySize) return E_INVALIDARG; - if ( IsPalettized(fmt) ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if (IsPalettized(fmt)) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); - if ( !_CalculateMipLevels(width,height,mipLevels) ) + if (!_CalculateMipLevels(width, height, mipLevels)) return E_INVALIDARG; Release(); - _metadata.width = width; - _metadata.height = height; - _metadata.depth = 1; - _metadata.arraySize = arraySize; - _metadata.mipLevels = mipLevels; - _metadata.miscFlags = 0; - _metadata.miscFlags2 = 0; - _metadata.format = fmt; - _metadata.dimension = TEX_DIMENSION_TEXTURE2D; + m_metadata.width = width; + m_metadata.height = height; + m_metadata.depth = 1; + m_metadata.arraySize = arraySize; + m_metadata.mipLevels = mipLevels; + m_metadata.miscFlags = 0; + m_metadata.miscFlags2 = 0; + m_metadata.format = fmt; + m_metadata.dimension = TEX_DIMENSION_TEXTURE2D; size_t pixelSize, nimages; - _DetermineImageArray( _metadata, flags, nimages, pixelSize ); + _DetermineImageArray(m_metadata, flags, nimages, pixelSize); - _image = new (std::nothrow) Image[ nimages ]; - if ( !_image ) + m_image = new (std::nothrow) Image[nimages]; + if (!m_image) return E_OUTOFMEMORY; - _nimages = nimages; - memset( _image, 0, sizeof(Image) * nimages ); + m_nimages = nimages; + memset(m_image, 0, sizeof(Image) * nimages); - _memory = reinterpret_cast( _aligned_malloc( pixelSize, 16 ) ); - if ( !_memory ) + m_memory = reinterpret_cast(_aligned_malloc(pixelSize, 16)); + if (!m_memory) { Release(); return E_OUTOFMEMORY; } - _size = pixelSize; - if ( !_SetupImageArray( _memory, pixelSize, _metadata, flags, _image, nimages ) ) + m_size = pixelSize; + if (!_SetupImageArray(m_memory, pixelSize, m_metadata, flags, m_image, nimages)) { Release(); return E_FAIL; @@ -405,50 +414,50 @@ 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, DWORD flags ) +HRESULT ScratchImage::Initialize3D(DXGI_FORMAT fmt, size_t width, size_t height, size_t depth, size_t mipLevels, DWORD flags) { - if ( !IsValid(fmt) || !width || !height || !depth ) + if (!IsValid(fmt) || !width || !height || !depth) return E_INVALIDARG; - if ( IsPalettized(fmt) ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if (IsPalettized(fmt)) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); - if ( !_CalculateMipLevels3D(width,height,depth,mipLevels) ) + if (!_CalculateMipLevels3D(width, height, depth, mipLevels)) return E_INVALIDARG; Release(); - _metadata.width = width; - _metadata.height = height; - _metadata.depth = depth; - _metadata.arraySize = 1; // Direct3D 10.x/11 does not support arrays of 3D textures - _metadata.mipLevels = mipLevels; - _metadata.miscFlags = 0; - _metadata.miscFlags2 = 0; - _metadata.format = fmt; - _metadata.dimension = TEX_DIMENSION_TEXTURE3D; + m_metadata.width = width; + m_metadata.height = height; + m_metadata.depth = depth; + m_metadata.arraySize = 1; // Direct3D 10.x/11 does not support arrays of 3D textures + m_metadata.mipLevels = mipLevels; + m_metadata.miscFlags = 0; + m_metadata.miscFlags2 = 0; + m_metadata.format = fmt; + m_metadata.dimension = TEX_DIMENSION_TEXTURE3D; size_t pixelSize, nimages; - _DetermineImageArray( _metadata, flags, nimages, pixelSize ); + _DetermineImageArray(m_metadata, flags, nimages, pixelSize); - _image = new (std::nothrow) Image[ nimages ]; - if ( !_image ) + m_image = new (std::nothrow) Image[nimages]; + if (!m_image) { Release(); return E_OUTOFMEMORY; } - _nimages = nimages; - memset( _image, 0, sizeof(Image) * nimages ); + m_nimages = nimages; + memset(m_image, 0, sizeof(Image) * nimages); - _memory = reinterpret_cast( _aligned_malloc( pixelSize, 16 ) ); - if ( !_memory ) + m_memory = reinterpret_cast(_aligned_malloc(pixelSize, 16)); + if (!m_memory) { Release(); return E_OUTOFMEMORY; } - _size = pixelSize; + m_size = pixelSize; - if ( !_SetupImageArray( _memory, pixelSize, _metadata, flags, _image, nimages ) ) + if (!_SetupImageArray(m_memory, pixelSize, m_metadata, flags, m_image, nimages)) { Release(); return E_FAIL; @@ -458,51 +467,51 @@ 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, DWORD flags ) +HRESULT ScratchImage::InitializeCube(DXGI_FORMAT fmt, size_t width, size_t height, size_t nCubes, size_t mipLevels, DWORD flags) { - if ( !width || !height || !nCubes ) + if (!width || !height || !nCubes) return E_INVALIDARG; // 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, flags ); - if ( FAILED(hr) ) + HRESULT hr = Initialize2D(fmt, width, height, nCubes * 6, mipLevels, flags); + if (FAILED(hr)) return hr; - _metadata.miscFlags |= TEX_MISC_TEXTURECUBE; + m_metadata.miscFlags |= TEX_MISC_TEXTURECUBE; return S_OK; } _Use_decl_annotations_ -HRESULT ScratchImage::InitializeFromImage( const Image& srcImage, bool allow1D, DWORD flags ) +HRESULT ScratchImage::InitializeFromImage(const Image& srcImage, bool allow1D, DWORD flags) { - HRESULT hr = ( srcImage.height > 1 || !allow1D ) - ? Initialize2D( srcImage.format, srcImage.width, srcImage.height, 1, 1, flags ) - : Initialize1D( srcImage.format, srcImage.width, 1, 1, flags ); + HRESULT hr = (srcImage.height > 1 || !allow1D) + ? Initialize2D(srcImage.format, srcImage.width, srcImage.height, 1, 1, flags) + : Initialize1D(srcImage.format, srcImage.width, 1, 1, flags); - if ( FAILED(hr) ) + if (FAILED(hr)) return hr; - size_t rowCount = ComputeScanlines( srcImage.format, srcImage.height ); - if ( !rowCount ) + size_t rowCount = ComputeScanlines(srcImage.format, srcImage.height); + if (!rowCount) return E_UNEXPECTED; - const uint8_t* sptr = reinterpret_cast( srcImage.pixels ); - if ( !sptr ) + const uint8_t* sptr = reinterpret_cast(srcImage.pixels); + if (!sptr) return E_POINTER; - auto dptr = reinterpret_cast( _image[0].pixels ); - if ( !dptr ) + auto dptr = reinterpret_cast(m_image[0].pixels); + if (!dptr) return E_POINTER; size_t spitch = srcImage.rowPitch; - size_t dpitch = _image[0].rowPitch; + size_t dpitch = m_image[0].rowPitch; - size_t size = std::min( dpitch, spitch ); + size_t size = std::min(dpitch, spitch); - for( size_t y = 0; y < rowCount; ++y ) + for (size_t y = 0; y < rowCount; ++y) { - memcpy_s( dptr, dpitch, sptr, size ); + memcpy_s(dptr, dpitch, sptr, size); sptr += spitch; dptr += dpitch; } @@ -511,57 +520,57 @@ HRESULT ScratchImage::InitializeFromImage( const Image& srcImage, bool allow1D, } _Use_decl_annotations_ -HRESULT ScratchImage::InitializeArrayFromImages( const Image* images, size_t nImages, bool allow1D, DWORD flags ) +HRESULT ScratchImage::InitializeArrayFromImages(const Image* images, size_t nImages, bool allow1D, DWORD flags) { - if ( !images || !nImages ) + if (!images || !nImages) return E_INVALIDARG; DXGI_FORMAT format = images[0].format; size_t width = images[0].width; size_t height = images[0].height; - for( size_t index=0; index < nImages; ++index ) + for (size_t index = 0; index < nImages; ++index) { - if ( !images[index].pixels ) + if (!images[index].pixels) return E_POINTER; - if ( images[index].format != format || images[index].width != width || images[index].height != height ) + if (images[index].format != format || images[index].width != width || images[index].height != height) { // All images must be the same format, width, and height return E_FAIL; } } - HRESULT hr = ( height > 1 || !allow1D ) - ? Initialize2D( format, width, height, nImages, 1, flags ) - : Initialize1D( format, width, nImages, 1, flags ); + HRESULT hr = (height > 1 || !allow1D) + ? Initialize2D(format, width, height, nImages, 1, flags) + : Initialize1D(format, width, nImages, 1, flags); - if ( FAILED(hr) ) + if (FAILED(hr)) return hr; - size_t rowCount = ComputeScanlines( format, height ); - if ( !rowCount ) + size_t rowCount = ComputeScanlines(format, height); + if (!rowCount) return E_UNEXPECTED; - for( size_t index=0; index < nImages; ++index ) + for (size_t index = 0; index < nImages; ++index) { - auto sptr = reinterpret_cast( images[index].pixels ); - if ( !sptr ) + auto sptr = reinterpret_cast(images[index].pixels); + if (!sptr) return E_POINTER; - assert( index < _nimages ); - auto dptr = reinterpret_cast( _image[index].pixels ); - if ( !dptr ) + assert(index < m_nimages); + auto dptr = reinterpret_cast(m_image[index].pixels); + if (!dptr) return E_POINTER; size_t spitch = images[index].rowPitch; - size_t dpitch = _image[index].rowPitch; + size_t dpitch = m_image[index].rowPitch; - size_t size = std::min( dpitch, spitch ); + size_t size = std::min(dpitch, spitch); - for( size_t y = 0; y < rowCount; ++y ) + for (size_t y = 0; y < rowCount; ++y) { - memcpy_s( dptr, dpitch, sptr, size ); + memcpy_s(dptr, dpitch, sptr, size); sptr += spitch; dptr += dpitch; } @@ -571,73 +580,73 @@ HRESULT ScratchImage::InitializeArrayFromImages( const Image* images, size_t nIm } _Use_decl_annotations_ -HRESULT ScratchImage::InitializeCubeFromImages( const Image* images, size_t nImages, DWORD flags ) +HRESULT ScratchImage::InitializeCubeFromImages(const Image* images, size_t nImages, DWORD flags) { - if ( !images || !nImages ) + if (!images || !nImages) return E_INVALIDARG; // A DirectX11 cubemap is just a 2D texture array that is a multiple of 6 for each cube - if ( ( nImages % 6 ) != 0 ) + if ((nImages % 6) != 0) return E_INVALIDARG; - HRESULT hr = InitializeArrayFromImages( images, nImages, false, flags ); - if ( FAILED(hr) ) + HRESULT hr = InitializeArrayFromImages(images, nImages, false, flags); + if (FAILED(hr)) return hr; - _metadata.miscFlags |= TEX_MISC_TEXTURECUBE; + m_metadata.miscFlags |= TEX_MISC_TEXTURECUBE; return S_OK; } _Use_decl_annotations_ -HRESULT ScratchImage::Initialize3DFromImages( const Image* images, size_t depth, DWORD flags ) +HRESULT ScratchImage::Initialize3DFromImages(const Image* images, size_t depth, DWORD flags) { - if ( !images || !depth ) + if (!images || !depth) return E_INVALIDARG; DXGI_FORMAT format = images[0].format; size_t width = images[0].width; size_t height = images[0].height; - for( size_t slice=0; slice < depth; ++slice ) + for (size_t slice = 0; slice < depth; ++slice) { - if ( !images[slice].pixels ) + if (!images[slice].pixels) return E_POINTER; - if ( images[slice].format != format || images[slice].width != width || images[slice].height != height ) + if (images[slice].format != format || images[slice].width != width || images[slice].height != height) { // All images must be the same format, width, and height return E_FAIL; } } - HRESULT hr = Initialize3D( format, width, height, depth, 1, flags ); - if ( FAILED(hr) ) + HRESULT hr = Initialize3D(format, width, height, depth, 1, flags); + if (FAILED(hr)) return hr; - size_t rowCount = ComputeScanlines( format, height ); - if ( !rowCount ) + size_t rowCount = ComputeScanlines(format, height); + if (!rowCount) return E_UNEXPECTED; - for( size_t slice=0; slice < depth; ++slice ) + for (size_t slice = 0; slice < depth; ++slice) { - auto sptr = reinterpret_cast( images[slice].pixels ); - if ( !sptr ) + auto sptr = reinterpret_cast(images[slice].pixels); + if (!sptr) return E_POINTER; - assert( slice < _nimages ); - auto dptr = reinterpret_cast( _image[slice].pixels ); - if ( !dptr ) + assert(slice < m_nimages); + auto dptr = reinterpret_cast(m_image[slice].pixels); + if (!dptr) return E_POINTER; size_t spitch = images[slice].rowPitch; - size_t dpitch = _image[slice].rowPitch; + size_t dpitch = m_image[slice].rowPitch; - size_t size = std::min( dpitch, spitch ); + size_t size = std::min(dpitch, spitch); - for( size_t y = 0; y < rowCount; ++y ) + for (size_t y = 0; y < rowCount; ++y) { - memcpy_s( dptr, dpitch, sptr, size ); + memcpy_s(dptr, dpitch, sptr, size); sptr += spitch; dptr += dpitch; } @@ -648,39 +657,39 @@ HRESULT ScratchImage::Initialize3DFromImages( const Image* images, size_t depth, void ScratchImage::Release() { - _nimages = 0; - _size = 0; + m_nimages = 0; + m_size = 0; - if ( _image ) + if (m_image) { - delete [] _image; - _image = 0; + delete[] m_image; + m_image = nullptr; } - if ( _memory ) + if (m_memory) { - _aligned_free( _memory ); - _memory = 0; + _aligned_free(m_memory); + m_memory = nullptr; } - - memset(&_metadata, 0, sizeof(_metadata)); + + memset(&m_metadata, 0, sizeof(m_metadata)); } _Use_decl_annotations_ -bool ScratchImage::OverrideFormat( DXGI_FORMAT f ) +bool ScratchImage::OverrideFormat(DXGI_FORMAT f) { - if ( !_image ) + if (!m_image) return false; - if ( !IsValid( f ) || IsPlanar( f ) || IsPalettized( f ) ) + if (!IsValid(f) || IsPlanar(f) || IsPalettized(f)) return false; - for( size_t index = 0; index < _nimages; ++index ) + for (size_t index = 0; index < m_nimages; ++index) { - _image[ index ].format = f; + m_image[index].format = f; } - _metadata.format = f; + m_metadata.format = f; return true; } @@ -688,42 +697,42 @@ bool ScratchImage::OverrideFormat( DXGI_FORMAT f ) _Use_decl_annotations_ const Image* ScratchImage::GetImage(size_t mip, size_t item, size_t slice) const { - if ( mip >= _metadata.mipLevels ) + if (mip >= m_metadata.mipLevels) return nullptr; size_t index = 0; - switch( _metadata.dimension ) + switch (m_metadata.dimension) { case TEX_DIMENSION_TEXTURE1D: case TEX_DIMENSION_TEXTURE2D: - if ( slice > 0 ) + if (slice > 0) return nullptr; - if ( item >= _metadata.arraySize ) + if (item >= m_metadata.arraySize) return nullptr; - index = item*( _metadata.mipLevels ) + mip; + index = item*(m_metadata.mipLevels) + mip; break; case TEX_DIMENSION_TEXTURE3D: - if ( item > 0 ) + if (item > 0) { // No support for arrays of volumes return nullptr; } else { - size_t d = _metadata.depth; + size_t d = m_metadata.depth; - for( size_t level = 0; level < mip; ++level ) + for (size_t level = 0; level < mip; ++level) { index += d; - if ( d > 1 ) + if (d > 1) d >>= 1; } - if ( slice >= d ) + if (slice >= d) return nullptr; index += slice; @@ -733,52 +742,52 @@ const Image* ScratchImage::GetImage(size_t mip, size_t item, size_t slice) const default: return nullptr; } - - return &_image[index]; + + return &m_image[index]; } bool ScratchImage::IsAlphaAllOpaque() const { - if ( !_image ) + if (!m_image) return false; - if ( !HasAlpha( _metadata.format ) ) + if (!HasAlpha(m_metadata.format)) return true; - if ( IsCompressed( _metadata.format ) ) + if (IsCompressed(m_metadata.format)) { - for( size_t index = 0; index < _nimages; ++index ) + for (size_t index = 0; index < m_nimages; ++index) { - if ( !_IsAlphaAllOpaqueBC( _image[ index ] ) ) + if (!_IsAlphaAllOpaqueBC(m_image[index])) return false; } } else { - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( (sizeof(XMVECTOR)*_metadata.width), 16 ) ) ); - if ( !scanline ) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc((sizeof(XMVECTOR)*m_metadata.width), 16))); + if (!scanline) return false; static const XMVECTORF32 threshold = { 0.99f, 0.99f, 0.99f, 0.99f }; - for( size_t index = 0; index < _nimages; ++index ) + for (size_t index = 0; index < m_nimages; ++index) { #pragma warning( suppress : 6011 ) - const Image& img = _image[ index ]; + const Image& img = m_image[index]; const uint8_t *pPixels = img.pixels; - assert( pPixels ); + assert(pPixels); - for( size_t h = 0; h < img.height; ++h ) + for (size_t h = 0; h < img.height; ++h) { - if ( !_LoadScanline( scanline.get(), img.width, pPixels, img.rowPitch, img.format ) ) + if (!_LoadScanline(scanline.get(), img.width, pPixels, img.rowPitch, img.format)) return false; XMVECTOR* ptr = scanline.get(); - for( size_t w = 0; w < img.width; ++w ) + for (size_t w = 0; w < img.width; ++w) { - XMVECTOR alpha = XMVectorSplatW( *ptr ); - if ( XMVector4Less( alpha, threshold ) ) + XMVECTOR alpha = XMVectorSplatW(*ptr); + if (XMVector4Less(alpha, threshold)) return false; ++ptr; } @@ -790,5 +799,3 @@ bool ScratchImage::IsAlphaAllOpaque() const return true; } - -}; // namespace diff --git a/DirectXTex/DirectXTexMipmaps.cpp b/DirectXTex/DirectXTexMipmaps.cpp index cca11d5..ec11166 100644 --- a/DirectXTex/DirectXTexMipmaps.cpp +++ b/DirectXTex/DirectXTexMipmaps.cpp @@ -17,1402 +17,1467 @@ #include "filters.h" +using namespace DirectX; using Microsoft::WRL::ComPtr; -namespace DirectX +namespace { - -//------------------------------------------------------------------------------------- -// Mipmap helper functions -//------------------------------------------------------------------------------------- -inline static bool ispow2( _In_ size_t x ) -{ - return ((x != 0) && !(x & (x - 1))); -} - - -//--- mipmap (1D/2D) levels computation --- -static size_t _CountMips( _In_ size_t width, _In_ size_t height ) -{ - size_t mipLevels = 1; - - while ( height > 1 || width > 1 ) + inline bool ispow2(_In_ size_t x) { - if ( height > 1 ) - height >>= 1; - - if ( width > 1 ) - width >>= 1; - - ++mipLevels; + return ((x != 0) && !(x & (x - 1))); } - - return mipLevels; -} -bool _CalculateMipLevels( _In_ size_t width, _In_ size_t height, _Inout_ size_t& mipLevels ) -{ - if ( mipLevels > 1 ) + + size_t _CountMips(_In_ size_t width, _In_ size_t height) { - size_t maxMips = _CountMips(width,height); - if ( mipLevels > maxMips ) - return false; - } - else if ( mipLevels == 0 ) - { - mipLevels = _CountMips(width,height); - } - else - { - mipLevels = 1; - } - return true; -} + size_t mipLevels = 1; - -//--- volume mipmap (3D) levels computation --- -static size_t _CountMips3D( _In_ size_t width, _In_ size_t height, _In_ size_t depth ) -{ - size_t mipLevels = 1; - - while ( height > 1 || width > 1 || depth > 1 ) - { - if ( height > 1 ) - height >>= 1; - - if ( width > 1 ) - width >>= 1; - - if ( depth > 1 ) - depth >>= 1; - - ++mipLevels; - } - - return mipLevels; -} - -bool _CalculateMipLevels3D( _In_ size_t width, _In_ size_t height, _In_ size_t depth, _Inout_ size_t& mipLevels ) -{ - if ( mipLevels > 1 ) - { - size_t maxMips = _CountMips3D(width,height,depth); - if ( mipLevels > maxMips ) - return false; - } - else if ( mipLevels == 0 ) - { - mipLevels = _CountMips3D(width,height,depth); - } - else - { - mipLevels = 1; - } - return true; -} - - -//------------------------------------------------------------------------------------- -// WIC related helper functions -//------------------------------------------------------------------------------------- -static HRESULT _EnsureWicBitmapPixelFormat( _In_ IWICImagingFactory* pWIC, _In_ IWICBitmap* src, _In_ DWORD filter, - _In_ const WICPixelFormatGUID& desiredPixelFormat, - _Deref_out_ IWICBitmap** dest ) -{ - if ( !pWIC || !src || !dest ) - return E_POINTER; - - *dest = nullptr; - - WICPixelFormatGUID actualPixelFormat; - HRESULT hr = src->GetPixelFormat( &actualPixelFormat ); - - if ( SUCCEEDED(hr) ) - { - if ( memcmp( &actualPixelFormat, &desiredPixelFormat, sizeof(WICPixelFormatGUID) ) == 0 ) + while (height > 1 || width > 1) { - src->AddRef(); - *dest = src; - } - else - { - ComPtr converter; - hr = pWIC->CreateFormatConverter( converter.GetAddressOf() ); + if (height > 1) + height >>= 1; - if ( SUCCEEDED(hr) ) - { - BOOL canConvert = FALSE; - hr = converter->CanConvert( actualPixelFormat, desiredPixelFormat, &canConvert ); - if ( FAILED(hr) || !canConvert ) - { - return E_UNEXPECTED; - } - } + if (width > 1) + width >>= 1; - if ( SUCCEEDED(hr) ) - { - hr = converter->Initialize( src, desiredPixelFormat, _GetWICDither(filter), 0, 0, WICBitmapPaletteTypeCustom ); - } - - if ( SUCCEEDED(hr) ) - { - hr = pWIC->CreateBitmapFromSource( converter.Get(), WICBitmapCacheOnDemand, dest ); - } - } - } - - return hr; -} - - -//--- Resizing color and alpha channels separately using WIC --- -HRESULT _ResizeSeparateColorAndAlpha( _In_ IWICImagingFactory* pWIC, _In_ bool iswic2, _In_ IWICBitmap* original, - _In_ size_t newWidth, _In_ size_t newHeight, _In_ DWORD filter, _Inout_ const Image* img ) -{ - if ( !pWIC || !original || !img ) - return E_POINTER; - - const WICBitmapInterpolationMode interpolationMode = _GetWICInterp(filter); - - WICPixelFormatGUID desiredPixelFormat = GUID_WICPixelFormatUndefined; - HRESULT hr = original->GetPixelFormat( &desiredPixelFormat ); - - size_t colorBytesInPixel = 0; - size_t colorBytesPerPixel = 0; - size_t colorWithAlphaBytesPerPixel = 0; - WICPixelFormatGUID colorPixelFormat = GUID_WICPixelFormatUndefined; - WICPixelFormatGUID colorWithAlphaPixelFormat = GUID_WICPixelFormatUndefined; - - if ( SUCCEEDED(hr) ) - { - ComPtr componentInfo; - hr = pWIC->CreateComponentInfo( desiredPixelFormat, componentInfo.GetAddressOf() ); - - ComPtr pixelFormatInfo; - if ( SUCCEEDED(hr) ) - { - hr = componentInfo.As( &pixelFormatInfo ); + ++mipLevels; } - UINT bitsPerPixel = 0; - if ( SUCCEEDED(hr) ) + return mipLevels; + } + + + size_t _CountMips3D(_In_ size_t width, _In_ size_t height, _In_ size_t depth) + { + size_t mipLevels = 1; + + while (height > 1 || width > 1 || depth > 1) { - hr = pixelFormatInfo->GetBitsPerPixel( &bitsPerPixel ); + if (height > 1) + height >>= 1; + + if (width > 1) + width >>= 1; + + if (depth > 1) + depth >>= 1; + + ++mipLevels; } - if ( SUCCEEDED(hr) ) - { - if ( bitsPerPixel <= 32 ) - { - colorBytesInPixel = colorBytesPerPixel = 3; - colorPixelFormat = GUID_WICPixelFormat24bppBGR; + return mipLevels; + } - colorWithAlphaBytesPerPixel = 4; - colorWithAlphaPixelFormat = GUID_WICPixelFormat32bppBGRA; + + HRESULT EnsureWicBitmapPixelFormat( + _In_ IWICImagingFactory* pWIC, + _In_ IWICBitmap* src, + _In_ DWORD filter, + _In_ const WICPixelFormatGUID& desiredPixelFormat, + _Deref_out_ IWICBitmap** dest) + { + if (!pWIC || !src || !dest) + return E_POINTER; + + *dest = nullptr; + + WICPixelFormatGUID actualPixelFormat; + HRESULT hr = src->GetPixelFormat(&actualPixelFormat); + + if (SUCCEEDED(hr)) + { + if (memcmp(&actualPixelFormat, &desiredPixelFormat, sizeof(WICPixelFormatGUID)) == 0) + { + src->AddRef(); + *dest = src; } else { + ComPtr converter; + hr = pWIC->CreateFormatConverter(converter.GetAddressOf()); + + if (SUCCEEDED(hr)) + { + BOOL canConvert = FALSE; + hr = converter->CanConvert(actualPixelFormat, desiredPixelFormat, &canConvert); + if (FAILED(hr) || !canConvert) + { + return E_UNEXPECTED; + } + } + + if (SUCCEEDED(hr)) + { + hr = converter->Initialize(src, desiredPixelFormat, _GetWICDither(filter), 0, 0, WICBitmapPaletteTypeCustom); + } + + if (SUCCEEDED(hr)) + { + hr = pWIC->CreateBitmapFromSource(converter.Get(), WICBitmapCacheOnDemand, dest); + } + } + } + + return hr; + } +} + + +namespace DirectX +{ + bool _CalculateMipLevels(_In_ size_t width, _In_ size_t height, _Inout_ size_t& mipLevels) + { + if (mipLevels > 1) + { + size_t maxMips = _CountMips(width, height); + if (mipLevels > maxMips) + return false; + } + else if (mipLevels == 0) + { + mipLevels = _CountMips(width, height); + } + else + { + mipLevels = 1; + } + return true; + } + + bool _CalculateMipLevels3D(_In_ size_t width, _In_ size_t height, _In_ size_t depth, _Inout_ size_t& mipLevels) + { + if (mipLevels > 1) + { + size_t maxMips = _CountMips3D(width, height, depth); + if (mipLevels > maxMips) + return false; + } + else if (mipLevels == 0) + { + mipLevels = _CountMips3D(width, height, depth); + } + else + { + mipLevels = 1; + } + return true; + } + + //--- Resizing color and alpha channels separately using WIC --- + HRESULT _ResizeSeparateColorAndAlpha( + _In_ IWICImagingFactory* pWIC, + _In_ bool iswic2, + _In_ IWICBitmap* original, + _In_ size_t newWidth, + _In_ size_t newHeight, + _In_ DWORD filter, + _Inout_ const Image* img) + { + if (!pWIC || !original || !img) + return E_POINTER; + + const WICBitmapInterpolationMode interpolationMode = _GetWICInterp(filter); + + WICPixelFormatGUID desiredPixelFormat = GUID_WICPixelFormatUndefined; + HRESULT hr = original->GetPixelFormat(&desiredPixelFormat); + + size_t colorBytesInPixel = 0; + size_t colorBytesPerPixel = 0; + size_t colorWithAlphaBytesPerPixel = 0; + WICPixelFormatGUID colorPixelFormat = GUID_WICPixelFormatUndefined; + WICPixelFormatGUID colorWithAlphaPixelFormat = GUID_WICPixelFormatUndefined; + + if (SUCCEEDED(hr)) + { + ComPtr componentInfo; + hr = pWIC->CreateComponentInfo(desiredPixelFormat, componentInfo.GetAddressOf()); + + ComPtr pixelFormatInfo; + if (SUCCEEDED(hr)) + { + hr = componentInfo.As(&pixelFormatInfo); + } + + UINT bitsPerPixel = 0; + if (SUCCEEDED(hr)) + { + hr = pixelFormatInfo->GetBitsPerPixel(&bitsPerPixel); + } + + if (SUCCEEDED(hr)) + { + if (bitsPerPixel <= 32) + { + colorBytesInPixel = colorBytesPerPixel = 3; + colorPixelFormat = GUID_WICPixelFormat24bppBGR; + + colorWithAlphaBytesPerPixel = 4; + colorWithAlphaPixelFormat = GUID_WICPixelFormat32bppBGRA; + } + else + { #if(_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE) - if ( iswic2 ) - { - colorBytesInPixel = colorBytesPerPixel = 12; - colorPixelFormat = GUID_WICPixelFormat96bppRGBFloat; - } - else + if (iswic2) + { + colorBytesInPixel = colorBytesPerPixel = 12; + colorPixelFormat = GUID_WICPixelFormat96bppRGBFloat; + } + else #else - UNREFERENCED_PARAMETER(iswic2); + UNREFERENCED_PARAMETER(iswic2); #endif - { - colorBytesInPixel = 12; - colorBytesPerPixel = 16; - colorPixelFormat = GUID_WICPixelFormat128bppRGBFloat; - } + { + colorBytesInPixel = 12; + colorBytesPerPixel = 16; + colorPixelFormat = GUID_WICPixelFormat128bppRGBFloat; + } - colorWithAlphaBytesPerPixel = 16; - colorWithAlphaPixelFormat = GUID_WICPixelFormat128bppRGBAFloat; - } - } - } - - // Resize color only image (no alpha channel) - ComPtr resizedColor; - if ( SUCCEEDED(hr) ) - { - ComPtr colorScaler; - hr = pWIC->CreateBitmapScaler( colorScaler.GetAddressOf() ); - if ( SUCCEEDED(hr) ) - { - ComPtr converted; - hr = _EnsureWicBitmapPixelFormat( pWIC, original, filter, colorPixelFormat, converted.GetAddressOf() ); - if ( SUCCEEDED(hr) ) - { - hr = colorScaler->Initialize( converted.Get(), static_cast(newWidth), static_cast(newHeight), interpolationMode ); - } - } - - if ( SUCCEEDED(hr) ) - { - ComPtr resized; - hr = pWIC->CreateBitmapFromSource( colorScaler.Get(), WICBitmapCacheOnDemand, resized.GetAddressOf() ); - if ( SUCCEEDED(hr) ) - { - hr = _EnsureWicBitmapPixelFormat( pWIC, resized.Get(), filter, colorPixelFormat, resizedColor.GetAddressOf() ); - } - } - } - - // Resize color+alpha image - ComPtr resizedColorWithAlpha; - if ( SUCCEEDED(hr) ) - { - ComPtr colorWithAlphaScaler; - hr = pWIC->CreateBitmapScaler( colorWithAlphaScaler.GetAddressOf() ); - if ( SUCCEEDED(hr) ) - { - ComPtr converted; - hr = _EnsureWicBitmapPixelFormat( pWIC, original, filter, colorWithAlphaPixelFormat, converted.GetAddressOf() ); - if ( SUCCEEDED(hr) ) - { - hr = colorWithAlphaScaler->Initialize( converted.Get(), static_cast(newWidth), static_cast(newHeight), interpolationMode ); - } - } - - if ( SUCCEEDED(hr) ) - { - ComPtr resized; - hr = pWIC->CreateBitmapFromSource( colorWithAlphaScaler.Get(), WICBitmapCacheOnDemand, resized.GetAddressOf() ); - if ( SUCCEEDED(hr) ) - { - hr = _EnsureWicBitmapPixelFormat( pWIC, resized.Get(), filter, colorWithAlphaPixelFormat, resizedColorWithAlpha.GetAddressOf() ); - } - } - } - - // Merge pixels (copying color channels from color only image to color+alpha image) - if ( SUCCEEDED(hr) ) - { - ComPtr colorLock; - ComPtr colorWithAlphaLock; - hr = resizedColor->Lock( nullptr, WICBitmapLockRead, colorLock.GetAddressOf() ); - if ( SUCCEEDED(hr) ) - { - hr = resizedColorWithAlpha->Lock( nullptr, WICBitmapLockWrite, colorWithAlphaLock.GetAddressOf() ); - } - - if ( SUCCEEDED(hr) ) - { - WICInProcPointer colorWithAlphaData = nullptr; - UINT colorWithAlphaSizeInBytes = 0; - UINT colorWithAlphaStride = 0; - - hr = colorWithAlphaLock->GetDataPointer( &colorWithAlphaSizeInBytes, &colorWithAlphaData ); - if ( SUCCEEDED(hr) ) - { - if ( !colorWithAlphaData ) - { - hr = E_POINTER; + colorWithAlphaBytesPerPixel = 16; + colorWithAlphaPixelFormat = GUID_WICPixelFormat128bppRGBAFloat; } - else + } + } + + // Resize color only image (no alpha channel) + ComPtr resizedColor; + if (SUCCEEDED(hr)) + { + ComPtr colorScaler; + hr = pWIC->CreateBitmapScaler(colorScaler.GetAddressOf()); + if (SUCCEEDED(hr)) + { + ComPtr converted; + hr = EnsureWicBitmapPixelFormat(pWIC, original, filter, colorPixelFormat, converted.GetAddressOf()); + if (SUCCEEDED(hr)) { - hr = colorWithAlphaLock->GetStride( &colorWithAlphaStride ); + hr = colorScaler->Initialize(converted.Get(), static_cast(newWidth), static_cast(newHeight), interpolationMode); } } - WICInProcPointer colorData = nullptr; - UINT colorSizeInBytes = 0; - UINT colorStride = 0; - if ( SUCCEEDED(hr) ) + if (SUCCEEDED(hr)) { - hr = colorLock->GetDataPointer( &colorSizeInBytes, &colorData ); - if ( SUCCEEDED(hr) ) + ComPtr resized; + hr = pWIC->CreateBitmapFromSource(colorScaler.Get(), WICBitmapCacheOnDemand, resized.GetAddressOf()); + if (SUCCEEDED(hr)) { - if ( !colorData ) + hr = EnsureWicBitmapPixelFormat(pWIC, resized.Get(), filter, colorPixelFormat, resizedColor.GetAddressOf()); + } + } + } + + // Resize color+alpha image + ComPtr resizedColorWithAlpha; + if (SUCCEEDED(hr)) + { + ComPtr colorWithAlphaScaler; + hr = pWIC->CreateBitmapScaler(colorWithAlphaScaler.GetAddressOf()); + if (SUCCEEDED(hr)) + { + ComPtr converted; + hr = EnsureWicBitmapPixelFormat(pWIC, original, filter, colorWithAlphaPixelFormat, converted.GetAddressOf()); + if (SUCCEEDED(hr)) + { + hr = colorWithAlphaScaler->Initialize(converted.Get(), static_cast(newWidth), static_cast(newHeight), interpolationMode); + } + } + + if (SUCCEEDED(hr)) + { + ComPtr resized; + hr = pWIC->CreateBitmapFromSource(colorWithAlphaScaler.Get(), WICBitmapCacheOnDemand, resized.GetAddressOf()); + if (SUCCEEDED(hr)) + { + hr = EnsureWicBitmapPixelFormat(pWIC, resized.Get(), filter, colorWithAlphaPixelFormat, resizedColorWithAlpha.GetAddressOf()); + } + } + } + + // Merge pixels (copying color channels from color only image to color+alpha image) + if (SUCCEEDED(hr)) + { + ComPtr colorLock; + ComPtr colorWithAlphaLock; + hr = resizedColor->Lock(nullptr, WICBitmapLockRead, colorLock.GetAddressOf()); + if (SUCCEEDED(hr)) + { + hr = resizedColorWithAlpha->Lock(nullptr, WICBitmapLockWrite, colorWithAlphaLock.GetAddressOf()); + } + + if (SUCCEEDED(hr)) + { + WICInProcPointer colorWithAlphaData = nullptr; + UINT colorWithAlphaSizeInBytes = 0; + UINT colorWithAlphaStride = 0; + + hr = colorWithAlphaLock->GetDataPointer(&colorWithAlphaSizeInBytes, &colorWithAlphaData); + if (SUCCEEDED(hr)) + { + if (!colorWithAlphaData) { hr = E_POINTER; } else { - hr = colorLock->GetStride( &colorStride ); + hr = colorWithAlphaLock->GetStride(&colorWithAlphaStride); } } - } - - for ( size_t j = 0; SUCCEEDED(hr) && j < newHeight; j++ ) - { - for ( size_t i = 0; SUCCEEDED(hr) && i < newWidth; i++ ) + + WICInProcPointer colorData = nullptr; + UINT colorSizeInBytes = 0; + UINT colorStride = 0; + if (SUCCEEDED(hr)) { - size_t colorWithAlphaIndex = (j * colorWithAlphaStride) + (i * colorWithAlphaBytesPerPixel); - size_t colorIndex = (j * colorStride) + (i * colorBytesPerPixel); - - if ( ((colorWithAlphaIndex + colorBytesInPixel) > colorWithAlphaSizeInBytes) - || ( (colorIndex + colorBytesPerPixel) > colorSizeInBytes) ) + hr = colorLock->GetDataPointer(&colorSizeInBytes, &colorData); + if (SUCCEEDED(hr)) { - hr = E_INVALIDARG; + if (!colorData) + { + hr = E_POINTER; + } + else + { + hr = colorLock->GetStride(&colorStride); + } } - else + } + + for (size_t j = 0; SUCCEEDED(hr) && j < newHeight; j++) + { + for (size_t i = 0; SUCCEEDED(hr) && i < newWidth; i++) { + size_t colorWithAlphaIndex = (j * colorWithAlphaStride) + (i * colorWithAlphaBytesPerPixel); + size_t colorIndex = (j * colorStride) + (i * colorBytesPerPixel); + + if (((colorWithAlphaIndex + colorBytesInPixel) > colorWithAlphaSizeInBytes) + || ((colorIndex + colorBytesPerPixel) > colorSizeInBytes)) + { + hr = E_INVALIDARG; + } + else + { #pragma warning( suppress : 26014 6386 ) // No overflow possible here - memcpy_s( colorWithAlphaData + colorWithAlphaIndex, colorWithAlphaBytesPerPixel, colorData + colorIndex, colorBytesInPixel ); + memcpy_s(colorWithAlphaData + colorWithAlphaIndex, colorWithAlphaBytesPerPixel, colorData + colorIndex, colorBytesInPixel); + } } } } } - } - if ( SUCCEEDED(hr) ) - { - ComPtr wicBitmap; - hr = _EnsureWicBitmapPixelFormat( pWIC, resizedColorWithAlpha.Get(), filter, desiredPixelFormat, wicBitmap.GetAddressOf() ); - if ( SUCCEEDED(hr) ) + if (SUCCEEDED(hr)) { - hr = wicBitmap->CopyPixels( nullptr, static_cast(img->rowPitch), static_cast(img->slicePitch), img->pixels ); + ComPtr wicBitmap; + hr = EnsureWicBitmapPixelFormat(pWIC, resizedColorWithAlpha.Get(), filter, desiredPixelFormat, wicBitmap.GetAddressOf()); + if (SUCCEEDED(hr)) + { + hr = wicBitmap->CopyPixels(nullptr, static_cast(img->rowPitch), static_cast(img->slicePitch), img->pixels); + } } - } - return hr; + return hr; + } } - -//--- determine when to use WIC vs. non-WIC paths --- -static bool _UseWICFiltering( _In_ DXGI_FORMAT format, _In_ DWORD filter ) +namespace { - if ( filter & TEX_FILTER_FORCE_NON_WIC ) + //--- determine when to use WIC vs. non-WIC paths --- + bool UseWICFiltering(_In_ DXGI_FORMAT format, _In_ DWORD filter) { - // Explicit flag indicates use of non-WIC code paths - return false; - } + if (filter & TEX_FILTER_FORCE_NON_WIC) + { + // Explicit flag indicates use of non-WIC code paths + return false; + } + + if (filter & TEX_FILTER_FORCE_WIC) + { + // Explicit flag to use WIC code paths, skips all the case checks below + return true; + } + + if (IsSRGB(format) || (filter & TEX_FILTER_SRGB)) + { + // Use non-WIC code paths for sRGB correct filtering + return false; + } + +#if defined(_XBOX_ONE) && defined(_TITLE) + if (format == DXGI_FORMAT_R16G16B16A16_FLOAT + || format == DXGI_FORMAT_R16_FLOAT) + { + // Use non-WIC code paths as these conversions are not supported by Xbox One XDK + return false; + } +#endif + + static_assert(TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK"); + + switch (filter & TEX_FILTER_MASK) + { + case TEX_FILTER_LINEAR: + if (filter & TEX_FILTER_WRAP) + { + // WIC only supports 'clamp' semantics (MIRROR is equivalent to clamp for linear) + return false; + } + + if (BitsPerColor(format) > 8) + { + // Avoid the WIC bitmap scaler when doing Linear filtering of XR/HDR formats + return false; + } + break; + + case TEX_FILTER_CUBIC: + if (filter & (TEX_FILTER_WRAP | TEX_FILTER_MIRROR)) + { + // WIC only supports 'clamp' semantics + return false; + } + + if (BitsPerColor(format) > 8) + { + // Avoid the WIC bitmap scaler when doing Cubic filtering of XR/HDR formats + return false; + } + break; + + case TEX_FILTER_TRIANGLE: + // WIC does not implement this filter + return false; + } - if ( filter & TEX_FILTER_FORCE_WIC ) - { - // Explicit flag to use WIC code paths, skips all the case checks below return true; } - if ( IsSRGB(format) || (filter & TEX_FILTER_SRGB) ) + + //--- mipmap (1D/2D) generation using WIC image scalar --- + HRESULT GenerateMipMapsUsingWIC( + _In_ const Image& baseImage, + _In_ DWORD filter, + _In_ size_t levels, + _In_ const WICPixelFormatGUID& pfGUID, + _In_ const ScratchImage& mipChain, + _In_ size_t item) { - // Use non-WIC code paths for sRGB correct filtering - return false; - } + assert(levels > 1); -#if defined(_XBOX_ONE) && defined(_TITLE) - if ( format == DXGI_FORMAT_R16G16B16A16_FLOAT - || format == DXGI_FORMAT_R16_FLOAT ) - { - // Use non-WIC code paths as these conversions are not supported by Xbox One XDK - return false; - } -#endif - - static_assert( TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK" ); - - switch ( filter & TEX_FILTER_MASK ) - { - case TEX_FILTER_LINEAR: - if ( filter & TEX_FILTER_WRAP ) - { - // WIC only supports 'clamp' semantics (MIRROR is equivalent to clamp for linear) - return false; - } - - if ( BitsPerColor(format) > 8 ) - { - // Avoid the WIC bitmap scaler when doing Linear filtering of XR/HDR formats - return false; - } - break; - - case TEX_FILTER_CUBIC: - if ( filter & ( TEX_FILTER_WRAP | TEX_FILTER_MIRROR ) ) - { - // WIC only supports 'clamp' semantics - return false; - } - - if ( BitsPerColor(format) > 8 ) - { - // Avoid the WIC bitmap scaler when doing Cubic filtering of XR/HDR formats - return false; - } - break; - - case TEX_FILTER_TRIANGLE: - // WIC does not implement this filter - return false; - } - - return true; -} - - -//--- mipmap (1D/2D) generation using WIC image scalar --- -static HRESULT _GenerateMipMapsUsingWIC( _In_ const Image& baseImage, _In_ DWORD filter, _In_ size_t levels, - _In_ const WICPixelFormatGUID& pfGUID, _In_ const ScratchImage& mipChain, _In_ size_t item ) -{ - assert( levels > 1 ); - - if ( !baseImage.pixels || !mipChain.GetPixels() ) - return E_POINTER; - - bool iswic2 = false; - IWICImagingFactory* pWIC = GetWICFactory(iswic2); - if ( !pWIC ) - return E_NOINTERFACE; - - size_t width = baseImage.width; - size_t height = baseImage.height; - - ComPtr source; - HRESULT hr = pWIC->CreateBitmapFromMemory( static_cast( width ), static_cast( height ), pfGUID, - static_cast( baseImage.rowPitch ), static_cast( baseImage.slicePitch ), - baseImage.pixels, source.GetAddressOf() ); - if ( FAILED(hr) ) - return hr; - - // Copy base image to top miplevel - const Image *img0 = mipChain.GetImage( 0, item, 0 ); - if ( !img0 ) - return E_POINTER; - - uint8_t* pDest = img0->pixels; - if ( !pDest ) - return E_POINTER; - - const uint8_t *pSrc = baseImage.pixels; - for( size_t h=0; h < height; ++h ) - { - size_t msize = std::min( img0->rowPitch, baseImage.rowPitch ); - memcpy_s( pDest, img0->rowPitch, pSrc, msize ); - pSrc += baseImage.rowPitch; - pDest += img0->rowPitch; - } - - ComPtr componentInfo; - hr = pWIC->CreateComponentInfo( pfGUID, componentInfo.GetAddressOf() ); - if ( FAILED(hr) ) - return hr; - - ComPtr pixelFormatInfo; - hr = componentInfo.As( &pixelFormatInfo ); - if ( FAILED(hr) ) - return hr; - - BOOL supportsTransparency = FALSE; - hr = pixelFormatInfo->SupportsTransparency( &supportsTransparency ); - if ( FAILED(hr) ) - return hr; - - // Resize base image to each target mip level - for( size_t level = 1; level < levels; ++level ) - { - const Image *img = mipChain.GetImage( level, item, 0 ); - if ( !img ) + if (!baseImage.pixels || !mipChain.GetPixels()) return E_POINTER; - if ( height > 1 ) - height >>= 1; + bool iswic2 = false; + IWICImagingFactory* pWIC = GetWICFactory(iswic2); + if (!pWIC) + return E_NOINTERFACE; - if ( width > 1 ) - width >>= 1; + size_t width = baseImage.width; + size_t height = baseImage.height; - assert( img->width == width && img->height == height && img->format == baseImage.format ); + ComPtr source; + HRESULT hr = pWIC->CreateBitmapFromMemory(static_cast(width), static_cast(height), pfGUID, + static_cast(baseImage.rowPitch), static_cast(baseImage.slicePitch), + baseImage.pixels, source.GetAddressOf()); + if (FAILED(hr)) + return hr; - if ( (filter & TEX_FILTER_SEPARATE_ALPHA) && supportsTransparency ) + // Copy base image to top miplevel + const Image *img0 = mipChain.GetImage(0, item, 0); + if (!img0) + return E_POINTER; + + uint8_t* pDest = img0->pixels; + if (!pDest) + return E_POINTER; + + const uint8_t *pSrc = baseImage.pixels; + for (size_t h = 0; h < height; ++h) { - hr = _ResizeSeparateColorAndAlpha( pWIC, iswic2, source.Get(), width, height, filter, img ); - if ( FAILED(hr) ) - return hr; + size_t msize = std::min(img0->rowPitch, baseImage.rowPitch); + memcpy_s(pDest, img0->rowPitch, pSrc, msize); + pSrc += baseImage.rowPitch; + pDest += img0->rowPitch; } - else + + ComPtr componentInfo; + hr = pWIC->CreateComponentInfo(pfGUID, componentInfo.GetAddressOf()); + if (FAILED(hr)) + return hr; + + ComPtr pixelFormatInfo; + hr = componentInfo.As(&pixelFormatInfo); + if (FAILED(hr)) + return hr; + + BOOL supportsTransparency = FALSE; + hr = pixelFormatInfo->SupportsTransparency(&supportsTransparency); + if (FAILED(hr)) + return hr; + + // Resize base image to each target mip level + for (size_t level = 1; level < levels; ++level) { - ComPtr scaler; - hr = pWIC->CreateBitmapScaler( scaler.GetAddressOf() ); - if ( FAILED(hr) ) - return hr; + const Image *img = mipChain.GetImage(level, item, 0); + if (!img) + return E_POINTER; - hr = scaler->Initialize( source.Get(), static_cast( width ), static_cast( height ), _GetWICInterp( filter ) ); - if ( FAILED(hr) ) - return hr; + if (height > 1) + height >>= 1; - WICPixelFormatGUID pfScaler; - hr = scaler->GetPixelFormat( &pfScaler ); - if ( FAILED(hr) ) - return hr; + if (width > 1) + width >>= 1; - if ( memcmp( &pfScaler, &pfGUID, sizeof(WICPixelFormatGUID) ) == 0 ) + assert(img->width == width && img->height == height && img->format == baseImage.format); + + if ((filter & TEX_FILTER_SEPARATE_ALPHA) && supportsTransparency) { - hr = scaler->CopyPixels( 0, static_cast( img->rowPitch ), static_cast( img->slicePitch ), img->pixels ); - if ( FAILED(hr) ) + hr = _ResizeSeparateColorAndAlpha(pWIC, iswic2, source.Get(), width, height, filter, img); + if (FAILED(hr)) return hr; } else { - // The WIC bitmap scaler is free to return a different pixel format than the source image, so here we - // convert it back - ComPtr FC; - hr = pWIC->CreateFormatConverter( FC.GetAddressOf() ); - if ( FAILED(hr) ) + ComPtr scaler; + hr = pWIC->CreateBitmapScaler(scaler.GetAddressOf()); + if (FAILED(hr)) return hr; - BOOL canConvert = FALSE; - hr = FC->CanConvert( pfScaler, pfGUID, &canConvert ); - if ( FAILED(hr) || !canConvert ) + hr = scaler->Initialize(source.Get(), static_cast(width), static_cast(height), _GetWICInterp(filter)); + if (FAILED(hr)) + return hr; + + WICPixelFormatGUID pfScaler; + hr = scaler->GetPixelFormat(&pfScaler); + if (FAILED(hr)) + return hr; + + if (memcmp(&pfScaler, &pfGUID, sizeof(WICPixelFormatGUID)) == 0) { - return E_UNEXPECTED; + hr = scaler->CopyPixels(0, static_cast(img->rowPitch), static_cast(img->slicePitch), img->pixels); + if (FAILED(hr)) + return hr; } + else + { + // The WIC bitmap scaler is free to return a different pixel format than the source image, so here we + // convert it back + ComPtr FC; + hr = pWIC->CreateFormatConverter(FC.GetAddressOf()); + if (FAILED(hr)) + return hr; - hr = FC->Initialize( scaler.Get(), pfGUID, _GetWICDither( filter ), 0, 0, WICBitmapPaletteTypeCustom ); - if ( FAILED(hr) ) - return hr; + BOOL canConvert = FALSE; + hr = FC->CanConvert(pfScaler, pfGUID, &canConvert); + if (FAILED(hr) || !canConvert) + { + return E_UNEXPECTED; + } - hr = FC->CopyPixels( 0, static_cast( img->rowPitch ), static_cast( img->slicePitch ), img->pixels ); - if ( FAILED(hr) ) - return hr; + hr = FC->Initialize(scaler.Get(), pfGUID, _GetWICDither(filter), 0, 0, WICBitmapPaletteTypeCustom); + if (FAILED(hr)) + return hr; + + hr = FC->CopyPixels(0, static_cast(img->rowPitch), static_cast(img->slicePitch), img->pixels); + if (FAILED(hr)) + return hr; + } } } + + return S_OK; } - return S_OK; -} - -//------------------------------------------------------------------------------------- -// Generate (1D/2D) mip-map helpers (custom filtering) -//------------------------------------------------------------------------------------- -static HRESULT _Setup2DMips( _In_reads_(nimages) const Image* baseImages, _In_ size_t nimages, _In_ const TexMetadata& mdata, - _Out_ ScratchImage& mipChain ) -{ - if ( !baseImages || !nimages ) - return E_INVALIDARG; - - assert( mdata.mipLevels > 1 ); - assert( mdata.arraySize == nimages ); - assert( mdata.depth == 1 && mdata.dimension != TEX_DIMENSION_TEXTURE3D ); - assert( mdata.width == baseImages[0].width ); - assert( mdata.height == baseImages[0].height ); - assert( mdata.format == baseImages[0].format ); - - HRESULT hr = mipChain.Initialize( mdata ); - if ( FAILED(hr) ) - return hr; - - // Copy base image(s) to top of mip chain - for( size_t item=0; item < nimages; ++item ) + //------------------------------------------------------------------------------------- + // Generate (1D/2D) mip-map helpers (custom filtering) + //------------------------------------------------------------------------------------- + HRESULT Setup2DMips( + _In_reads_(nimages) const Image* baseImages, + _In_ size_t nimages, + _In_ const TexMetadata& mdata, + _Out_ ScratchImage& mipChain) { - const Image& src = baseImages[item]; + if (!baseImages || !nimages) + return E_INVALIDARG; - const Image *dest = mipChain.GetImage( 0, item, 0 ); - if ( !dest ) + assert(mdata.mipLevels > 1); + assert(mdata.arraySize == nimages); + assert(mdata.depth == 1 && mdata.dimension != TEX_DIMENSION_TEXTURE3D); + assert(mdata.width == baseImages[0].width); + assert(mdata.height == baseImages[0].height); + assert(mdata.format == baseImages[0].format); + + HRESULT hr = mipChain.Initialize(mdata); + if (FAILED(hr)) + return hr; + + // Copy base image(s) to top of mip chain + for (size_t item = 0; item < nimages; ++item) { - mipChain.Release(); - return E_POINTER; + const Image& src = baseImages[item]; + + const Image *dest = mipChain.GetImage(0, item, 0); + if (!dest) + { + mipChain.Release(); + return E_POINTER; + } + + assert(src.format == dest->format); + + uint8_t* pDest = dest->pixels; + if (!pDest) + { + mipChain.Release(); + return E_POINTER; + } + + const uint8_t *pSrc = src.pixels; + size_t rowPitch = src.rowPitch; + for (size_t h = 0; h < mdata.height; ++h) + { + size_t msize = std::min(dest->rowPitch, rowPitch); + memcpy_s(pDest, dest->rowPitch, pSrc, msize); + pSrc += rowPitch; + pDest += dest->rowPitch; + } } - assert( src.format == dest->format ); - - uint8_t* pDest = dest->pixels; - if ( !pDest ) - { - mipChain.Release(); - return E_POINTER; - } - - const uint8_t *pSrc = src.pixels; - size_t rowPitch = src.rowPitch; - for( size_t h=0; h < mdata.height; ++h ) - { - size_t msize = std::min( dest->rowPitch, rowPitch ); - memcpy_s( pDest, dest->rowPitch, pSrc, msize ); - pSrc += rowPitch; - pDest += dest->rowPitch; - } + return S_OK; } - return S_OK; -} - -//--- 2D Point Filter --- -static HRESULT _Generate2DMipsPointFilter( _In_ size_t levels, _In_ const ScratchImage& mipChain, _In_ size_t item ) -{ - if ( !mipChain.GetImages() ) - return E_INVALIDARG; - - // This assumes that the base image is already placed into the mipChain at the top level... (see _Setup2DMips) - - assert( levels > 1 ); - - size_t width = mipChain.GetMetadata().width; - size_t height = mipChain.GetMetadata().height; - - // Allocate temporary space (2 scanlines) - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( (sizeof(XMVECTOR)*width*2), 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - XMVECTOR* target = scanline.get(); - - XMVECTOR* row = target + width; - - // Resize base image to each target mip level - for( size_t level=1; level < levels; ++level ) + //--- 2D Point Filter --- + HRESULT Generate2DMipsPointFilter(size_t levels, const ScratchImage& mipChain, size_t item) { + if (!mipChain.GetImages()) + return E_INVALIDARG; + + // This assumes that the base image is already placed into the mipChain at the top level... (see _Setup2DMips) + + assert(levels > 1); + + size_t width = mipChain.GetMetadata().width; + size_t height = mipChain.GetMetadata().height; + + // Allocate temporary space (2 scanlines) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc((sizeof(XMVECTOR)*width * 2), 16))); + if (!scanline) + return E_OUTOFMEMORY; + + XMVECTOR* target = scanline.get(); + + XMVECTOR* row = target + width; + + // Resize base image to each target mip level + for (size_t level = 1; level < levels; ++level) + { #ifdef _DEBUG - memset( row, 0xCD, sizeof(XMVECTOR)*width ); + memset(row, 0xCD, sizeof(XMVECTOR)*width); #endif - // 2D point filter - const Image* src = mipChain.GetImage( level-1, item, 0 ); - const Image* dest = mipChain.GetImage( level, item, 0 ); + // 2D point filter + const Image* src = mipChain.GetImage(level - 1, item, 0); + const Image* dest = mipChain.GetImage(level, item, 0); - if ( !src || !dest ) - return E_POINTER; + if (!src || !dest) + return E_POINTER; - const uint8_t* pSrc = src->pixels; - uint8_t* pDest = dest->pixels; + const uint8_t* pSrc = src->pixels; + uint8_t* pDest = dest->pixels; - size_t rowPitch = src->rowPitch; + size_t rowPitch = src->rowPitch; - size_t nwidth = (width > 1) ? (width >> 1) : 1; - size_t nheight = (height > 1) ? (height >> 1) : 1; + size_t nwidth = (width > 1) ? (width >> 1) : 1; + size_t nheight = (height > 1) ? (height >> 1) : 1; - size_t xinc = ( width << 16 ) / nwidth; - size_t yinc = ( height << 16 ) / nheight; + size_t xinc = (width << 16) / nwidth; + size_t yinc = (height << 16) / nheight; - size_t lasty = size_t(-1); + size_t lasty = size_t(-1); - size_t sy = 0; - for( size_t y = 0; y < nheight; ++y ) - { - if ( (lasty ^ sy) >> 16 ) + size_t sy = 0; + for (size_t y = 0; y < nheight; ++y) { - if ( !_LoadScanline( row, width, pSrc + ( rowPitch * (sy >> 16) ), rowPitch, src->format ) ) + if ((lasty ^ sy) >> 16) + { + if (!_LoadScanline(row, width, pSrc + (rowPitch * (sy >> 16)), rowPitch, src->format)) + return E_FAIL; + lasty = sy; + } + + size_t sx = 0; + for (size_t x = 0; x < nwidth; ++x) + { + target[x] = row[sx >> 16]; + sx += xinc; + } + + if (!_StoreScanline(pDest, dest->rowPitch, dest->format, target, nwidth)) return E_FAIL; - lasty = sy; + pDest += dest->rowPitch; + + sy += yinc; } - size_t sx = 0; - for( size_t x = 0; x < nwidth; ++x ) - { - target[ x ] = row[ sx >> 16 ]; - sx += xinc; - } + if (height > 1) + height >>= 1; - if ( !_StoreScanline( pDest, dest->rowPitch, dest->format, target, nwidth ) ) - return E_FAIL; - pDest += dest->rowPitch; - - sy += yinc; + if (width > 1) + width >>= 1; } - if ( height > 1 ) - height >>= 1; - - if ( width > 1 ) - width >>= 1; + return S_OK; } - return S_OK; -} - -//--- 2D Box Filter --- -static HRESULT _Generate2DMipsBoxFilter( _In_ size_t levels, _In_ DWORD filter, _In_ const ScratchImage& mipChain, _In_ size_t item ) -{ - if ( !mipChain.GetImages() ) - return E_INVALIDARG; - - // This assumes that the base image is already placed into the mipChain at the top level... (see _Setup2DMips) - - assert( levels > 1 ); - - size_t width = mipChain.GetMetadata().width; - size_t height = mipChain.GetMetadata().height; - - if ( !ispow2(width) || !ispow2(height) ) - return E_FAIL; - - // Allocate temporary space (3 scanlines) - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( (sizeof(XMVECTOR)*width*3), 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - XMVECTOR* target = scanline.get(); - - XMVECTOR* urow0 = target + width; - XMVECTOR* urow1 = target + width*2; - - const XMVECTOR* urow2 = urow0 + 1; - const XMVECTOR* urow3 = urow1 + 1; - - // Resize base image to each target mip level - for( size_t level=1; level < levels; ++level ) + //--- 2D Box Filter --- + HRESULT Generate2DMipsBoxFilter(size_t levels, DWORD filter, const ScratchImage& mipChain, size_t item) { - if ( height <= 1 ) + if (!mipChain.GetImages()) + return E_INVALIDARG; + + // This assumes that the base image is already placed into the mipChain at the top level... (see _Setup2DMips) + + assert(levels > 1); + + size_t width = mipChain.GetMetadata().width; + size_t height = mipChain.GetMetadata().height; + + if (!ispow2(width) || !ispow2(height)) + return E_FAIL; + + // Allocate temporary space (3 scanlines) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc((sizeof(XMVECTOR)*width * 3), 16))); + if (!scanline) + return E_OUTOFMEMORY; + + XMVECTOR* target = scanline.get(); + + XMVECTOR* urow0 = target + width; + XMVECTOR* urow1 = target + width * 2; + + const XMVECTOR* urow2 = urow0 + 1; + const XMVECTOR* urow3 = urow1 + 1; + + // Resize base image to each target mip level + for (size_t level = 1; level < levels; ++level) { - urow1 = urow0; - } - - if ( width <= 1 ) - { - urow2 = urow0; - urow3 = urow1; - } - - // 2D box filter - const Image* src = mipChain.GetImage( level-1, item, 0 ); - const Image* dest = mipChain.GetImage( level, item, 0 ); - - if ( !src || !dest ) - return E_POINTER; - - const uint8_t* pSrc = src->pixels; - uint8_t* pDest = dest->pixels; - - size_t rowPitch = src->rowPitch; - - size_t nwidth = (width > 1) ? (width >> 1) : 1; - size_t nheight = (height > 1) ? (height >> 1) : 1; - - for( size_t y = 0; y < nheight; ++y ) - { - if ( !_LoadScanlineLinear( urow0, width, pSrc, rowPitch, src->format, filter ) ) - return E_FAIL; - pSrc += rowPitch; - - if ( urow0 != urow1 ) + if (height <= 1) { - if ( !_LoadScanlineLinear( urow1, width, pSrc, rowPitch, src->format, filter ) ) + urow1 = urow0; + } + + if (width <= 1) + { + urow2 = urow0; + urow3 = urow1; + } + + // 2D box filter + const Image* src = mipChain.GetImage(level - 1, item, 0); + const Image* dest = mipChain.GetImage(level, item, 0); + + if (!src || !dest) + return E_POINTER; + + const uint8_t* pSrc = src->pixels; + uint8_t* pDest = dest->pixels; + + size_t rowPitch = src->rowPitch; + + size_t nwidth = (width > 1) ? (width >> 1) : 1; + size_t nheight = (height > 1) ? (height >> 1) : 1; + + for (size_t y = 0; y < nheight; ++y) + { + if (!_LoadScanlineLinear(urow0, width, pSrc, rowPitch, src->format, filter)) return E_FAIL; pSrc += rowPitch; - } - for( size_t x = 0; x < nwidth; ++x ) - { - size_t x2 = x << 1; - - AVERAGE4( target[ x ], urow0[ x2 ], urow1[ x2 ], urow2[ x2 ], urow3[ x2 ] ); - } - - if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) ) - return E_FAIL; - pDest += dest->rowPitch; - } - - if ( height > 1 ) - height >>= 1; - - if ( width > 1 ) - width >>= 1; - } - - return S_OK; -} - - -//--- 2D Linear Filter --- -static HRESULT _Generate2DMipsLinearFilter( _In_ size_t levels, _In_ DWORD filter, _In_ const ScratchImage& mipChain, _In_ size_t item ) -{ - if ( !mipChain.GetImages() ) - return E_INVALIDARG; - - // This assumes that the base image is already placed into the mipChain at the top level... (see _Setup2DMips) - - assert( levels > 1 ); - - size_t width = mipChain.GetMetadata().width; - size_t height = mipChain.GetMetadata().height; - - // Allocate temporary space (3 scanlines, plus X and Y filters) - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( (sizeof(XMVECTOR)*width*3), 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - std::unique_ptr lf( new (std::nothrow) LinearFilter[ width+height ] ); - if ( !lf ) - return E_OUTOFMEMORY; - - LinearFilter* lfX = lf.get(); - LinearFilter* lfY = lf.get() + width; - - XMVECTOR* target = scanline.get(); - - XMVECTOR* row0 = target + width; - XMVECTOR* row1 = target + width*2; - - // Resize base image to each target mip level - for( size_t level=1; level < levels; ++level ) - { - // 2D linear filter - const Image* src = mipChain.GetImage( level-1, item, 0 ); - const Image* dest = mipChain.GetImage( level, item, 0 ); - - if ( !src || !dest ) - return E_POINTER; - - const uint8_t* pSrc = src->pixels; - uint8_t* pDest = dest->pixels; - - size_t rowPitch = src->rowPitch; - - size_t nwidth = (width > 1) ? (width >> 1) : 1; - _CreateLinearFilter( width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, lfX ); - - size_t nheight = (height > 1) ? (height >> 1) : 1; - _CreateLinearFilter( height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, lfY ); - -#ifdef _DEBUG - memset( row0, 0xCD, sizeof(XMVECTOR)*width ); - memset( row1, 0xDD, sizeof(XMVECTOR)*width ); -#endif - - size_t u0 = size_t(-1); - size_t u1 = size_t(-1); - - for( size_t y = 0; y < nheight; ++y ) - { - auto& toY = lfY[ y ]; - - if ( toY.u0 != u0 ) - { - if ( toY.u0 != u1 ) + if (urow0 != urow1) { - u0 = toY.u0; - - if ( !_LoadScanlineLinear( row0, width, pSrc + (rowPitch * u0), rowPitch, src->format, filter ) ) + if (!_LoadScanlineLinear(urow1, width, pSrc, rowPitch, src->format, filter)) return E_FAIL; + pSrc += rowPitch; } - else + + for (size_t x = 0; x < nwidth; ++x) { - u0 = u1; - u1 = size_t(-1); + size_t x2 = x << 1; - std::swap( row0, row1 ); + AVERAGE4(target[x], urow0[x2], urow1[x2], urow2[x2], urow3[x2]); } - } - if ( toY.u1 != u1 ) - { - u1 = toY.u1; - - if ( !_LoadScanlineLinear( row1, width, pSrc + (rowPitch * u1), rowPitch, src->format, filter ) ) + if (!_StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter)) return E_FAIL; + pDest += dest->rowPitch; } - for( size_t x = 0; x < nwidth; ++x ) - { - auto& toX = lfX[ x ]; + if (height > 1) + height >>= 1; - BILINEAR_INTERPOLATE( target[x], toX, toY, row0, row1 ); - } - - if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) ) - return E_FAIL; - pDest += dest->rowPitch; + if (width > 1) + width >>= 1; } - if ( height > 1 ) - height >>= 1; - - if ( width > 1 ) - width >>= 1; + return S_OK; } - return S_OK; -} - -//--- 2D Cubic Filter --- -static HRESULT _Generate2DMipsCubicFilter( _In_ size_t levels, _In_ DWORD filter, _In_ const ScratchImage& mipChain, _In_ size_t item ) -{ - if ( !mipChain.GetImages() ) - return E_INVALIDARG; - - // This assumes that the base image is already placed into the mipChain at the top level... (see _Setup2DMips) - - assert( levels > 1 ); - - size_t width = mipChain.GetMetadata().width; - size_t height = mipChain.GetMetadata().height; - - // Allocate temporary space (5 scanlines, plus X and Y filters) - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( (sizeof(XMVECTOR)*width*5), 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - std::unique_ptr cf( new (std::nothrow) CubicFilter[ width+height ] ); - if ( !cf ) - return E_OUTOFMEMORY; - - CubicFilter* cfX = cf.get(); - CubicFilter* cfY = cf.get() + width; - - XMVECTOR* target = scanline.get(); - - XMVECTOR* row0 = target + width; - XMVECTOR* row1 = target + width*2; - XMVECTOR* row2 = target + width*3; - XMVECTOR* row3 = target + width*4; - - // Resize base image to each target mip level - for( size_t level=1; level < levels; ++level ) + //--- 2D Linear Filter --- + HRESULT Generate2DMipsLinearFilter(size_t levels, DWORD filter, const ScratchImage& mipChain, size_t item) { - // 2D cubic filter - const Image* src = mipChain.GetImage( level-1, item, 0 ); - const Image* dest = mipChain.GetImage( level, item, 0 ); + if (!mipChain.GetImages()) + return E_INVALIDARG; - if ( !src || !dest ) - return E_POINTER; + // This assumes that the base image is already placed into the mipChain at the top level... (see _Setup2DMips) - const uint8_t* pSrc = src->pixels; - uint8_t* pDest = dest->pixels; + assert(levels > 1); - size_t rowPitch = src->rowPitch; + size_t width = mipChain.GetMetadata().width; + size_t height = mipChain.GetMetadata().height; - size_t nwidth = (width > 1) ? (width >> 1) : 1; - _CreateCubicFilter( width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, (filter & TEX_FILTER_MIRROR_U) != 0, cfX ); + // Allocate temporary space (3 scanlines, plus X and Y filters) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc((sizeof(XMVECTOR)*width * 3), 16))); + if (!scanline) + return E_OUTOFMEMORY; - size_t nheight = (height > 1) ? (height >> 1) : 1; - _CreateCubicFilter( height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, (filter & TEX_FILTER_MIRROR_V) != 0, cfY ); + std::unique_ptr lf(new (std::nothrow) LinearFilter[width + height]); + if (!lf) + return E_OUTOFMEMORY; + + LinearFilter* lfX = lf.get(); + LinearFilter* lfY = lf.get() + width; + + XMVECTOR* target = scanline.get(); + + XMVECTOR* row0 = target + width; + XMVECTOR* row1 = target + width * 2; + + // Resize base image to each target mip level + for (size_t level = 1; level < levels; ++level) + { + // 2D linear filter + const Image* src = mipChain.GetImage(level - 1, item, 0); + const Image* dest = mipChain.GetImage(level, item, 0); + + if (!src || !dest) + return E_POINTER; + + const uint8_t* pSrc = src->pixels; + uint8_t* pDest = dest->pixels; + + size_t rowPitch = src->rowPitch; + + size_t nwidth = (width > 1) ? (width >> 1) : 1; + _CreateLinearFilter(width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, lfX); + + size_t nheight = (height > 1) ? (height >> 1) : 1; + _CreateLinearFilter(height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, lfY); #ifdef _DEBUG - memset( row0, 0xCD, sizeof(XMVECTOR)*width ); - memset( row1, 0xDD, sizeof(XMVECTOR)*width ); - memset( row2, 0xED, sizeof(XMVECTOR)*width ); - memset( row3, 0xFD, sizeof(XMVECTOR)*width ); + memset(row0, 0xCD, sizeof(XMVECTOR)*width); + memset(row1, 0xDD, sizeof(XMVECTOR)*width); #endif - size_t u0 = size_t(-1); - size_t u1 = size_t(-1); - size_t u2 = size_t(-1); - size_t u3 = size_t(-1); + size_t u0 = size_t(-1); + size_t u1 = size_t(-1); - for( size_t y = 0; y < nheight; ++y ) - { - auto& toY = cfY[ y ]; - - // Scanline 1 - if ( toY.u0 != u0 ) + for (size_t y = 0; y < nheight; ++y) { - if ( toY.u0 != u1 && toY.u0 != u2 && toY.u0 != u3 ) + auto& toY = lfY[y]; + + if (toY.u0 != u0) { - u0 = toY.u0; - - if ( !_LoadScanlineLinear( row0, width, pSrc + (rowPitch * u0), rowPitch, src->format, filter ) ) - return E_FAIL; - } - else if ( toY.u0 == u1 ) - { - u0 = u1; - u1 = size_t(-1); - - std::swap( row0, row1 ); - } - else if ( toY.u0 == u2 ) - { - u0 = u2; - u2 = size_t(-1); - - std::swap( row0, row2 ); - } - else if ( toY.u0 == u3 ) - { - u0 = u3; - u3 = size_t(-1); - - std::swap( row0, row3 ); - } - } - - // Scanline 2 - if ( toY.u1 != u1 ) - { - if ( toY.u1 != u2 && toY.u1 != u3 ) - { - u1 = toY.u1; - - if ( !_LoadScanlineLinear( row1, width, pSrc + (rowPitch * u1), rowPitch, src->format, filter ) ) - return E_FAIL; - } - else if ( toY.u1 == u2 ) - { - u1 = u2; - u2 = size_t(-1); - - std::swap( row1, row2 ); - } - else if ( toY.u1 == u3 ) - { - u1 = u3; - u3 = size_t(-1); - - std::swap( row1, row3 ); - } - } - - // Scanline 3 - if ( toY.u2 != u2 ) - { - if ( toY.u2 != u3 ) - { - u2 = toY.u2; - - if ( !_LoadScanlineLinear( row2, width, pSrc + (rowPitch * u2), rowPitch, src->format, filter ) ) - return E_FAIL; - } - else - { - u2 = u3; - u3 = size_t(-1); - - std::swap( row2, row3 ); - } - } - - // Scanline 4 - if ( toY.u3 != u3 ) - { - u3 = toY.u3; - - if ( !_LoadScanlineLinear( row3, width, pSrc + (rowPitch * u3), rowPitch, src->format, filter ) ) - return E_FAIL; - } - - for( size_t x = 0; x < nwidth; ++x ) - { - auto& toX = cfX[ x ]; - - XMVECTOR C0, C1, C2, C3; - - CUBIC_INTERPOLATE( C0, toX.x, row0[ toX.u0 ], row0[ toX.u1 ], row0[ toX.u2 ], row0[ toX.u3 ] ); - CUBIC_INTERPOLATE( C1, toX.x, row1[ toX.u0 ], row1[ toX.u1 ], row1[ toX.u2 ], row1[ toX.u3 ] ); - CUBIC_INTERPOLATE( C2, toX.x, row2[ toX.u0 ], row2[ toX.u1 ], row2[ toX.u2 ], row2[ toX.u3 ] ); - CUBIC_INTERPOLATE( C3, toX.x, row3[ toX.u0 ], row3[ toX.u1 ], row3[ toX.u2 ], row3[ toX.u3 ] ); - - CUBIC_INTERPOLATE( target[x], toY.x, C0, C1, C2, C3 ); - } - - if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) ) - return E_FAIL; - pDest += dest->rowPitch; - } - - if ( height > 1 ) - height >>= 1; - - if ( width > 1 ) - width >>= 1; - } - - return S_OK; -} - - -//--- 2D Triangle Filter --- -static HRESULT _Generate2DMipsTriangleFilter( _In_ size_t levels, _In_ DWORD filter, _In_ const ScratchImage& mipChain, _In_ size_t item ) -{ - if ( !mipChain.GetImages() ) - return E_INVALIDARG; - - using namespace TriangleFilter; - - // This assumes that the base image is already placed into the mipChain at the top level... (see _Setup2DMips) - - assert( levels > 1 ); - - size_t width = mipChain.GetMetadata().width; - size_t height = mipChain.GetMetadata().height; - - // Allocate initial temporary space (1 scanline, accumulation rows, plus X and Y filters) - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( sizeof(XMVECTOR) * width, 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - std::unique_ptr rowActive( new (std::nothrow) TriangleRow[ height ] ); - if ( !rowActive ) - return E_OUTOFMEMORY; - - TriangleRow * rowFree = nullptr; - - std::unique_ptr tfX, tfY; - - XMVECTOR* row = scanline.get(); - - // Resize base image to each target mip level - for( size_t level=1; level < levels; ++level ) - { - // 2D triangle filter - const Image* src = mipChain.GetImage( level-1, item, 0 ); - const Image* dest = mipChain.GetImage( level, item, 0 ); - - if ( !src || !dest ) - return E_POINTER; - - const uint8_t* pSrc = src->pixels; - size_t rowPitch = src->rowPitch; - const uint8_t* pEndSrc = pSrc + rowPitch * height; - - uint8_t* pDest = dest->pixels; - - size_t nwidth = (width > 1) ? (width >> 1) : 1; - HRESULT hr = _Create( width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, tfX ); - if ( FAILED(hr) ) - return hr; - - size_t nheight = (height > 1) ? (height >> 1) : 1; - hr = _Create( height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, tfY ); - if ( FAILED(hr) ) - return hr; - -#ifdef _DEBUG - memset( row, 0xCD, sizeof(XMVECTOR)*width ); -#endif - - auto xFromEnd = reinterpret_cast( reinterpret_cast( tfX.get() ) + tfX->sizeInBytes ); - auto yFromEnd = reinterpret_cast( reinterpret_cast( tfY.get() ) + tfY->sizeInBytes ); - - // Count times rows get written (and clear out any leftover accumulation rows from last miplevel) - for( FilterFrom* yFrom = tfY->from; yFrom < yFromEnd; ) - { - for ( size_t j = 0; j < yFrom->count; ++j ) - { - size_t v = yFrom->to[ j ].u; - assert( v < nheight ); - TriangleRow* rowAcc = &rowActive[ v ]; - - ++rowAcc->remaining; - - if ( rowAcc->scanline ) - { - memset( rowAcc->scanline.get(), 0, sizeof(XMVECTOR) * nwidth ); - } - } - - yFrom = reinterpret_cast( reinterpret_cast( yFrom ) + yFrom->sizeInBytes ); - } - - // Filter image - for( FilterFrom* yFrom = tfY->from; yFrom < yFromEnd; ) - { - // Create accumulation rows as needed - for ( size_t j = 0; j < yFrom->count; ++j ) - { - size_t v = yFrom->to[ j ].u; - assert( v < nheight ); - TriangleRow* rowAcc = &rowActive[ v ]; - - if ( !rowAcc->scanline ) - { - if ( rowFree ) + if (toY.u0 != u1) { - // Steal and reuse scanline from 'free row' list - // (it will always be at least as wide as nwidth due to loop decending order) - assert( rowFree->scanline != 0 ); - rowAcc->scanline.reset( rowFree->scanline.release() ); - rowFree = rowFree->next; + u0 = toY.u0; + + if (!_LoadScanlineLinear(row0, width, pSrc + (rowPitch * u0), rowPitch, src->format, filter)) + return E_FAIL; } else { - rowAcc->scanline.reset( reinterpret_cast( _aligned_malloc( sizeof(XMVECTOR) * nwidth, 16 ) ) ); - if ( !rowAcc->scanline ) - return E_OUTOFMEMORY; - } + u0 = u1; + u1 = size_t(-1); - memset( rowAcc->scanline.get(), 0, sizeof(XMVECTOR) * nwidth ); - } - } - - // Load source scanline - if ( (pSrc + rowPitch) > pEndSrc ) - return E_FAIL; - - if ( !_LoadScanlineLinear( row, width, pSrc, rowPitch, src->format, filter ) ) - return E_FAIL; - - pSrc += rowPitch; - - // Process row - size_t x = 0; - for( FilterFrom* xFrom = tfX->from; xFrom < xFromEnd; ++x ) - { - for ( size_t j = 0; j < yFrom->count; ++j ) - { - size_t v = yFrom->to[ j ].u; - assert( v < nheight ); - float yweight = yFrom->to[ j ].weight; - - XMVECTOR* accPtr = rowActive[ v ].scanline.get(); - if ( !accPtr ) - return E_POINTER; - - for ( size_t k = 0; k < xFrom->count; ++k ) - { - size_t u = xFrom->to[ k ].u; - assert( u < nwidth ); - - XMVECTOR weight = XMVectorReplicate( yweight * xFrom->to[ k ].weight ); - - assert( x < width ); - accPtr[ u ] = XMVectorMultiplyAdd( row[ x ], weight, accPtr[ u ] ); + std::swap(row0, row1); } } - xFrom = reinterpret_cast( reinterpret_cast( xFrom ) + xFrom->sizeInBytes ); + if (toY.u1 != u1) + { + u1 = toY.u1; + + if (!_LoadScanlineLinear(row1, width, pSrc + (rowPitch * u1), rowPitch, src->format, filter)) + return E_FAIL; + } + + for (size_t x = 0; x < nwidth; ++x) + { + auto& toX = lfX[x]; + + BILINEAR_INTERPOLATE(target[x], toX, toY, row0, row1); + } + + if (!_StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter)) + return E_FAIL; + pDest += dest->rowPitch; } - // Write completed accumulation rows - for ( size_t j = 0; j < yFrom->count; ++j ) + if (height > 1) + height >>= 1; + + if (width > 1) + width >>= 1; + } + + return S_OK; + } + + //--- 2D Cubic Filter --- + HRESULT Generate2DMipsCubicFilter(size_t levels, DWORD filter, const ScratchImage& mipChain, size_t item) + { + if (!mipChain.GetImages()) + return E_INVALIDARG; + + // This assumes that the base image is already placed into the mipChain at the top level... (see _Setup2DMips) + + assert(levels > 1); + + size_t width = mipChain.GetMetadata().width; + size_t height = mipChain.GetMetadata().height; + + // Allocate temporary space (5 scanlines, plus X and Y filters) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc((sizeof(XMVECTOR)*width * 5), 16))); + if (!scanline) + return E_OUTOFMEMORY; + + std::unique_ptr cf(new (std::nothrow) CubicFilter[width + height]); + if (!cf) + return E_OUTOFMEMORY; + + CubicFilter* cfX = cf.get(); + CubicFilter* cfY = cf.get() + width; + + XMVECTOR* target = scanline.get(); + + XMVECTOR* row0 = target + width; + XMVECTOR* row1 = target + width * 2; + XMVECTOR* row2 = target + width * 3; + XMVECTOR* row3 = target + width * 4; + + // Resize base image to each target mip level + for (size_t level = 1; level < levels; ++level) + { + // 2D cubic filter + const Image* src = mipChain.GetImage(level - 1, item, 0); + const Image* dest = mipChain.GetImage(level, item, 0); + + if (!src || !dest) + return E_POINTER; + + const uint8_t* pSrc = src->pixels; + uint8_t* pDest = dest->pixels; + + size_t rowPitch = src->rowPitch; + + size_t nwidth = (width > 1) ? (width >> 1) : 1; + _CreateCubicFilter(width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, (filter & TEX_FILTER_MIRROR_U) != 0, cfX); + + size_t nheight = (height > 1) ? (height >> 1) : 1; + _CreateCubicFilter(height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, (filter & TEX_FILTER_MIRROR_V) != 0, cfY); + +#ifdef _DEBUG + memset(row0, 0xCD, sizeof(XMVECTOR)*width); + memset(row1, 0xDD, sizeof(XMVECTOR)*width); + memset(row2, 0xED, sizeof(XMVECTOR)*width); + memset(row3, 0xFD, sizeof(XMVECTOR)*width); +#endif + + size_t u0 = size_t(-1); + size_t u1 = size_t(-1); + size_t u2 = size_t(-1); + size_t u3 = size_t(-1); + + for (size_t y = 0; y < nheight; ++y) { - size_t v = yFrom->to[ j ].u; - assert( v < nheight ); - TriangleRow* rowAcc = &rowActive[ v ]; + auto& toY = cfY[y]; - assert( rowAcc->remaining > 0 ); - --rowAcc->remaining; - - if ( !rowAcc->remaining ) + // Scanline 1 + if (toY.u0 != u0) { - XMVECTOR* pAccSrc = rowAcc->scanline.get(); - if ( !pAccSrc ) - return E_POINTER; - - switch( dest->format ) + if (toY.u0 != u1 && toY.u0 != u2 && toY.u0 != u3) { - case DXGI_FORMAT_R10G10B10A2_UNORM: - case DXGI_FORMAT_R10G10B10A2_UINT: + u0 = toY.u0; + + if (!_LoadScanlineLinear(row0, width, pSrc + (rowPitch * u0), rowPitch, src->format, filter)) + return E_FAIL; + } + else if (toY.u0 == u1) + { + u0 = u1; + u1 = size_t(-1); + + std::swap(row0, row1); + } + else if (toY.u0 == u2) + { + u0 = u2; + u2 = size_t(-1); + + std::swap(row0, row2); + } + else if (toY.u0 == u3) + { + u0 = u3; + u3 = size_t(-1); + + std::swap(row0, row3); + } + } + + // Scanline 2 + if (toY.u1 != u1) + { + if (toY.u1 != u2 && toY.u1 != u3) + { + u1 = toY.u1; + + if (!_LoadScanlineLinear(row1, width, pSrc + (rowPitch * u1), rowPitch, src->format, filter)) + return E_FAIL; + } + else if (toY.u1 == u2) + { + u1 = u2; + u2 = size_t(-1); + + std::swap(row1, row2); + } + else if (toY.u1 == u3) + { + u1 = u3; + u3 = size_t(-1); + + std::swap(row1, row3); + } + } + + // Scanline 3 + if (toY.u2 != u2) + { + if (toY.u2 != u3) + { + u2 = toY.u2; + + if (!_LoadScanlineLinear(row2, width, pSrc + (rowPitch * u2), rowPitch, src->format, filter)) + return E_FAIL; + } + else + { + u2 = u3; + u3 = size_t(-1); + + std::swap(row2, row3); + } + } + + // Scanline 4 + if (toY.u3 != u3) + { + u3 = toY.u3; + + if (!_LoadScanlineLinear(row3, width, pSrc + (rowPitch * u3), rowPitch, src->format, filter)) + return E_FAIL; + } + + for (size_t x = 0; x < nwidth; ++x) + { + auto& toX = cfX[x]; + + XMVECTOR C0, C1, C2, C3; + + CUBIC_INTERPOLATE(C0, toX.x, row0[toX.u0], row0[toX.u1], row0[toX.u2], row0[toX.u3]); + CUBIC_INTERPOLATE(C1, toX.x, row1[toX.u0], row1[toX.u1], row1[toX.u2], row1[toX.u3]); + CUBIC_INTERPOLATE(C2, toX.x, row2[toX.u0], row2[toX.u1], row2[toX.u2], row2[toX.u3]); + CUBIC_INTERPOLATE(C3, toX.x, row3[toX.u0], row3[toX.u1], row3[toX.u2], row3[toX.u3]); + + CUBIC_INTERPOLATE(target[x], toY.x, C0, C1, C2, C3); + } + + if (!_StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter)) + return E_FAIL; + pDest += dest->rowPitch; + } + + if (height > 1) + height >>= 1; + + if (width > 1) + width >>= 1; + } + + return S_OK; + } + + + //--- 2D Triangle Filter --- + HRESULT Generate2DMipsTriangleFilter(size_t levels, DWORD filter, const ScratchImage& mipChain, size_t item) + { + if (!mipChain.GetImages()) + return E_INVALIDARG; + + using namespace TriangleFilter; + + // This assumes that the base image is already placed into the mipChain at the top level... (see _Setup2DMips) + + assert(levels > 1); + + size_t width = mipChain.GetMetadata().width; + size_t height = mipChain.GetMetadata().height; + + // Allocate initial temporary space (1 scanline, accumulation rows, plus X and Y filters) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc(sizeof(XMVECTOR) * width, 16))); + if (!scanline) + return E_OUTOFMEMORY; + + std::unique_ptr rowActive(new (std::nothrow) TriangleRow[height]); + if (!rowActive) + return E_OUTOFMEMORY; + + TriangleRow * rowFree = nullptr; + + std::unique_ptr tfX, tfY; + + XMVECTOR* row = scanline.get(); + + // Resize base image to each target mip level + for (size_t level = 1; level < levels; ++level) + { + // 2D triangle filter + const Image* src = mipChain.GetImage(level - 1, item, 0); + const Image* dest = mipChain.GetImage(level, item, 0); + + if (!src || !dest) + return E_POINTER; + + const uint8_t* pSrc = src->pixels; + size_t rowPitch = src->rowPitch; + const uint8_t* pEndSrc = pSrc + rowPitch * height; + + uint8_t* pDest = dest->pixels; + + size_t nwidth = (width > 1) ? (width >> 1) : 1; + HRESULT hr = _Create(width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, tfX); + if (FAILED(hr)) + return hr; + + size_t nheight = (height > 1) ? (height >> 1) : 1; + hr = _Create(height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, tfY); + if (FAILED(hr)) + return hr; + +#ifdef _DEBUG + memset(row, 0xCD, sizeof(XMVECTOR)*width); +#endif + + auto xFromEnd = reinterpret_cast(reinterpret_cast(tfX.get()) + tfX->sizeInBytes); + auto yFromEnd = reinterpret_cast(reinterpret_cast(tfY.get()) + tfY->sizeInBytes); + + // Count times rows get written (and clear out any leftover accumulation rows from last miplevel) + for (FilterFrom* yFrom = tfY->from; yFrom < yFromEnd; ) + { + for (size_t j = 0; j < yFrom->count; ++j) + { + size_t v = yFrom->to[j].u; + assert(v < nheight); + TriangleRow* rowAcc = &rowActive[v]; + + ++rowAcc->remaining; + + if (rowAcc->scanline) + { + memset(rowAcc->scanline.get(), 0, sizeof(XMVECTOR) * nwidth); + } + } + + yFrom = reinterpret_cast(reinterpret_cast(yFrom) + yFrom->sizeInBytes); + } + + // Filter image + for (FilterFrom* yFrom = tfY->from; yFrom < yFromEnd; ) + { + // Create accumulation rows as needed + for (size_t j = 0; j < yFrom->count; ++j) + { + size_t v = yFrom->to[j].u; + assert(v < nheight); + TriangleRow* rowAcc = &rowActive[v]; + + if (!rowAcc->scanline) + { + if (rowFree) + { + // Steal and reuse scanline from 'free row' list + // (it will always be at least as wide as nwidth due to loop decending order) + assert(rowFree->scanline != 0); + rowAcc->scanline.reset(rowFree->scanline.release()); + rowFree = rowFree->next; + } + else + { + rowAcc->scanline.reset(reinterpret_cast(_aligned_malloc(sizeof(XMVECTOR) * nwidth, 16))); + if (!rowAcc->scanline) + return E_OUTOFMEMORY; + } + + memset(rowAcc->scanline.get(), 0, sizeof(XMVECTOR) * nwidth); + } + } + + // Load source scanline + if ((pSrc + rowPitch) > pEndSrc) + return E_FAIL; + + if (!_LoadScanlineLinear(row, width, pSrc, rowPitch, src->format, filter)) + return E_FAIL; + + pSrc += rowPitch; + + // Process row + size_t x = 0; + for (FilterFrom* xFrom = tfX->from; xFrom < xFromEnd; ++x) + { + for (size_t j = 0; j < yFrom->count; ++j) + { + size_t v = yFrom->to[j].u; + assert(v < nheight); + float yweight = yFrom->to[j].weight; + + XMVECTOR* accPtr = rowActive[v].scanline.get(); + if (!accPtr) + return E_POINTER; + + for (size_t k = 0; k < xFrom->count; ++k) + { + size_t u = xFrom->to[k].u; + assert(u < nwidth); + + XMVECTOR weight = XMVectorReplicate(yweight * xFrom->to[k].weight); + + assert(x < width); + accPtr[u] = XMVectorMultiplyAdd(row[x], weight, accPtr[u]); + } + } + + xFrom = reinterpret_cast(reinterpret_cast(xFrom) + xFrom->sizeInBytes); + } + + // Write completed accumulation rows + for (size_t j = 0; j < yFrom->count; ++j) + { + size_t v = yFrom->to[j].u; + assert(v < nheight); + TriangleRow* rowAcc = &rowActive[v]; + + assert(rowAcc->remaining > 0); + --rowAcc->remaining; + + if (!rowAcc->remaining) + { + XMVECTOR* pAccSrc = rowAcc->scanline.get(); + if (!pAccSrc) + return E_POINTER; + + switch (dest->format) + { + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: { // Need to slightly bias results for floating-point error accumulation which can // be visible with harshly quantized values static const XMVECTORF32 Bias = { 0.f, 0.f, 0.f, 0.1f }; - + XMVECTOR* ptr = pAccSrc; - for( size_t i=0; i < dest->width; ++i, ++ptr ) + for (size_t i = 0; i < dest->width; ++i, ++ptr) { - *ptr = XMVectorAdd( *ptr, Bias ); + *ptr = XMVectorAdd(*ptr, Bias); } } break; + } + + // This performs any required clamping + if (!_StoreScanlineLinear(pDest + (dest->rowPitch * v), dest->rowPitch, dest->format, pAccSrc, dest->width, filter)) + return E_FAIL; + + // Put row on freelist to reuse it's allocated scanline + rowAcc->next = rowFree; + rowFree = rowAcc; } - - // This performs any required clamping - if ( !_StoreScanlineLinear( pDest + (dest->rowPitch * v), dest->rowPitch, dest->format, pAccSrc, dest->width, filter ) ) - return E_FAIL; - - // Put row on freelist to reuse it's allocated scanline - rowAcc->next = rowFree; - rowFree = rowAcc; } + + yFrom = reinterpret_cast(reinterpret_cast(yFrom) + yFrom->sizeInBytes); } - yFrom = reinterpret_cast( reinterpret_cast( yFrom ) + yFrom->sizeInBytes ); + if (height > 1) + height >>= 1; + + if (width > 1) + width >>= 1; } - if ( height > 1 ) - height >>= 1; - - if ( width > 1 ) - width >>= 1; + return S_OK; } - return S_OK; -} - -//------------------------------------------------------------------------------------- -// Generate volume mip-map helpers -//------------------------------------------------------------------------------------- -static HRESULT _Setup3DMips( _In_reads_(depth) const Image* baseImages, _In_ size_t depth, size_t levels, - _Out_ ScratchImage& mipChain ) -{ - if ( !baseImages || !depth ) - return E_INVALIDARG; - - assert( levels > 1 ); - - size_t width = baseImages[0].width; - size_t height = baseImages[0].height; - - HRESULT hr = mipChain.Initialize3D( baseImages[0].format, width, height, depth, levels ); - if ( FAILED(hr) ) - return hr; - - // Copy base images to top slice - for( size_t slice=0; slice < depth; ++slice ) + //------------------------------------------------------------------------------------- + // Generate volume mip-map helpers + //------------------------------------------------------------------------------------- + HRESULT Setup3DMips( + _In_reads_(depth) const Image* baseImages, + size_t depth, + size_t levels, + _Out_ ScratchImage& mipChain) { - const Image& src = baseImages[slice]; + if (!baseImages || !depth) + return E_INVALIDARG; - const Image *dest = mipChain.GetImage( 0, 0, slice ); - if ( !dest ) + assert(levels > 1); + + size_t width = baseImages[0].width; + size_t height = baseImages[0].height; + + HRESULT hr = mipChain.Initialize3D(baseImages[0].format, width, height, depth, levels); + if (FAILED(hr)) + return hr; + + // Copy base images to top slice + for (size_t slice = 0; slice < depth; ++slice) { - mipChain.Release(); - return E_POINTER; + const Image& src = baseImages[slice]; + + const Image *dest = mipChain.GetImage(0, 0, slice); + if (!dest) + { + mipChain.Release(); + return E_POINTER; + } + + assert(src.format == dest->format); + + uint8_t* pDest = dest->pixels; + if (!pDest) + { + mipChain.Release(); + return E_POINTER; + } + + const uint8_t *pSrc = src.pixels; + size_t rowPitch = src.rowPitch; + for (size_t h = 0; h < height; ++h) + { + size_t msize = std::min(dest->rowPitch, rowPitch); + memcpy_s(pDest, dest->rowPitch, pSrc, msize); + pSrc += rowPitch; + pDest += dest->rowPitch; + } } - assert( src.format == dest->format ); - - uint8_t* pDest = dest->pixels; - if ( !pDest ) - { - mipChain.Release(); - return E_POINTER; - } - - const uint8_t *pSrc = src.pixels; - size_t rowPitch = src.rowPitch; - for( size_t h=0; h < height; ++h ) - { - size_t msize = std::min( dest->rowPitch, rowPitch ); - memcpy_s( pDest, dest->rowPitch, pSrc, msize ); - pSrc += rowPitch; - pDest += dest->rowPitch; - } + return S_OK; } - return S_OK; -} - -//--- 3D Point Filter --- -static HRESULT _Generate3DMipsPointFilter( _In_ size_t depth, _In_ size_t levels, _In_ const ScratchImage& mipChain ) -{ - if ( !depth || !mipChain.GetImages() ) - return E_INVALIDARG; - - // This assumes that the base images are already placed into the mipChain at the top level... (see _Setup3DMips) - - assert( levels > 1 ); - - size_t width = mipChain.GetMetadata().width; - size_t height = mipChain.GetMetadata().height; - - // Allocate temporary space (2 scanlines) - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( (sizeof(XMVECTOR)*width*2), 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - XMVECTOR* target = scanline.get(); - - XMVECTOR* row = target + width; - - // Resize base image to each target mip level - for( size_t level=1; level < levels; ++level ) + //--- 3D Point Filter --- + HRESULT Generate3DMipsPointFilter(size_t depth, size_t levels, const ScratchImage& mipChain) { + if (!depth || !mipChain.GetImages()) + return E_INVALIDARG; + + // This assumes that the base images are already placed into the mipChain at the top level... (see _Setup3DMips) + + assert(levels > 1); + + size_t width = mipChain.GetMetadata().width; + size_t height = mipChain.GetMetadata().height; + + // Allocate temporary space (2 scanlines) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc((sizeof(XMVECTOR)*width * 2), 16))); + if (!scanline) + return E_OUTOFMEMORY; + + XMVECTOR* target = scanline.get(); + + XMVECTOR* row = target + width; + + // Resize base image to each target mip level + for (size_t level = 1; level < levels; ++level) + { #ifdef _DEBUG - memset( row, 0xCD, sizeof(XMVECTOR)*width ); + memset(row, 0xCD, sizeof(XMVECTOR)*width); #endif - if ( depth > 1 ) - { - // 3D point filter - size_t ndepth = depth >> 1; - - size_t zinc = ( depth << 16 ) / ndepth; - - size_t sz = 0; - for( size_t slice=0; slice < ndepth; ++slice ) + if (depth > 1) { - const Image* src = mipChain.GetImage( level-1, 0, (sz >> 16) ); - const Image* dest = mipChain.GetImage( level, 0, slice ); + // 3D point filter + size_t ndepth = depth >> 1; - if ( !src || !dest ) + size_t zinc = (depth << 16) / ndepth; + + size_t sz = 0; + for (size_t slice = 0; slice < ndepth; ++slice) + { + const Image* src = mipChain.GetImage(level - 1, 0, (sz >> 16)); + const Image* dest = mipChain.GetImage(level, 0, slice); + + if (!src || !dest) + return E_POINTER; + + const uint8_t* pSrc = src->pixels; + uint8_t* pDest = dest->pixels; + + size_t rowPitch = src->rowPitch; + + size_t nwidth = (width > 1) ? (width >> 1) : 1; + size_t nheight = (height > 1) ? (height >> 1) : 1; + + size_t xinc = (width << 16) / nwidth; + size_t yinc = (height << 16) / nheight; + + size_t lasty = size_t(-1); + + size_t sy = 0; + for (size_t y = 0; y < nheight; ++y) + { + if ((lasty ^ sy) >> 16) + { + if (!_LoadScanline(row, width, pSrc + (rowPitch * (sy >> 16)), rowPitch, src->format)) + return E_FAIL; + lasty = sy; + } + + size_t sx = 0; + for (size_t x = 0; x < nwidth; ++x) + { + target[x] = row[sx >> 16]; + sx += xinc; + } + + if (!_StoreScanline(pDest, dest->rowPitch, dest->format, target, nwidth)) + return E_FAIL; + pDest += dest->rowPitch; + + sy += yinc; + } + + sz += zinc; + } + } + else + { + // 2D point filter + const Image* src = mipChain.GetImage(level - 1, 0, 0); + const Image* dest = mipChain.GetImage(level, 0, 0); + + if (!src || !dest) return E_POINTER; const uint8_t* pSrc = src->pixels; @@ -1423,356 +1488,369 @@ static HRESULT _Generate3DMipsPointFilter( _In_ size_t depth, _In_ size_t levels size_t nwidth = (width > 1) ? (width >> 1) : 1; size_t nheight = (height > 1) ? (height >> 1) : 1; - size_t xinc = ( width << 16 ) / nwidth; - size_t yinc = ( height << 16 ) / nheight; + size_t xinc = (width << 16) / nwidth; + size_t yinc = (height << 16) / nheight; size_t lasty = size_t(-1); size_t sy = 0; - for( size_t y = 0; y < nheight; ++y ) + for (size_t y = 0; y < nheight; ++y) { - if ( (lasty ^ sy) >> 16 ) + if ((lasty ^ sy) >> 16) { - if ( !_LoadScanline( row, width, pSrc + ( rowPitch * (sy >> 16) ), rowPitch, src->format ) ) + if (!_LoadScanline(row, width, pSrc + (rowPitch * (sy >> 16)), rowPitch, src->format)) return E_FAIL; lasty = sy; } size_t sx = 0; - for( size_t x = 0; x < nwidth; ++x ) + for (size_t x = 0; x < nwidth; ++x) { - target[ x ] = row[ sx >> 16 ]; + target[x] = row[sx >> 16]; sx += xinc; } - if ( !_StoreScanline( pDest, dest->rowPitch, dest->format, target, nwidth ) ) + if (!_StoreScanline(pDest, dest->rowPitch, dest->format, target, nwidth)) return E_FAIL; pDest += dest->rowPitch; sy += yinc; } - - sz += zinc; } - } - else - { - // 2D point filter - const Image* src = mipChain.GetImage( level-1, 0, 0 ); - const Image* dest = mipChain.GetImage( level, 0, 0 ); - if ( !src || !dest ) - return E_POINTER; + if (height > 1) + height >>= 1; - const uint8_t* pSrc = src->pixels; - uint8_t* pDest = dest->pixels; + if (width > 1) + width >>= 1; - size_t rowPitch = src->rowPitch; - - size_t nwidth = (width > 1) ? (width >> 1) : 1; - size_t nheight = (height > 1) ? (height >> 1) : 1; - - size_t xinc = ( width << 16 ) / nwidth; - size_t yinc = ( height << 16 ) / nheight; - - size_t lasty = size_t(-1); - - size_t sy = 0; - for( size_t y = 0; y < nheight; ++y ) - { - if ( (lasty ^ sy) >> 16 ) - { - if ( !_LoadScanline( row, width, pSrc + ( rowPitch * (sy >> 16) ), rowPitch, src->format ) ) - return E_FAIL; - lasty = sy; - } - - size_t sx = 0; - for( size_t x = 0; x < nwidth; ++x ) - { - target[ x ] = row[ sx >> 16 ]; - sx += xinc; - } - - if ( !_StoreScanline( pDest, dest->rowPitch, dest->format, target, nwidth ) ) - return E_FAIL; - pDest += dest->rowPitch; - - sy += yinc; - } + if (depth > 1) + depth >>= 1; } - if ( height > 1 ) - height >>= 1; - - if ( width > 1 ) - width >>= 1; - - if ( depth > 1 ) - depth >>= 1; + return S_OK; } - return S_OK; -} - -//--- 3D Box Filter --- -static HRESULT _Generate3DMipsBoxFilter( _In_ size_t depth, _In_ size_t levels, _In_ DWORD filter, _In_ const ScratchImage& mipChain ) -{ - if ( !depth || !mipChain.GetImages() ) - return E_INVALIDARG; - - // This assumes that the base images are already placed into the mipChain at the top level... (see _Setup3DMips) - - assert( levels > 1 ); - - size_t width = mipChain.GetMetadata().width; - size_t height = mipChain.GetMetadata().height; - - if ( !ispow2(width) || !ispow2(height) || !ispow2(depth) ) - return E_FAIL; - - // Allocate temporary space (5 scanlines) - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( (sizeof(XMVECTOR)*width*5), 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - XMVECTOR* target = scanline.get(); - - XMVECTOR* urow0 = target + width; - XMVECTOR* urow1 = target + width*2; - XMVECTOR* vrow0 = target + width*3; - XMVECTOR* vrow1 = target + width*4; - - const XMVECTOR* urow2 = urow0 + 1; - const XMVECTOR* urow3 = urow1 + 1; - const XMVECTOR* vrow2 = vrow0 + 1; - const XMVECTOR* vrow3 = vrow1 + 1; - - // Resize base image to each target mip level - for( size_t level=1; level < levels; ++level ) + //--- 3D Box Filter --- + HRESULT Generate3DMipsBoxFilter(size_t depth, size_t levels, DWORD filter, const ScratchImage& mipChain) { - if ( height <= 1 ) - { - urow1 = urow0; - vrow1 = vrow0; - } + if (!depth || !mipChain.GetImages()) + return E_INVALIDARG; - if ( width <= 1 ) - { - urow2 = urow0; - urow3 = urow1; - vrow2 = vrow0; - vrow3 = vrow1; - } + // This assumes that the base images are already placed into the mipChain at the top level... (see _Setup3DMips) - if ( depth > 1 ) - { - // 3D box filter - size_t ndepth = depth >> 1; + assert(levels > 1); - for( size_t slice=0; slice < ndepth; ++slice ) + size_t width = mipChain.GetMetadata().width; + size_t height = mipChain.GetMetadata().height; + + if (!ispow2(width) || !ispow2(height) || !ispow2(depth)) + return E_FAIL; + + // Allocate temporary space (5 scanlines) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc((sizeof(XMVECTOR)*width * 5), 16))); + if (!scanline) + return E_OUTOFMEMORY; + + XMVECTOR* target = scanline.get(); + + XMVECTOR* urow0 = target + width; + XMVECTOR* urow1 = target + width * 2; + XMVECTOR* vrow0 = target + width * 3; + XMVECTOR* vrow1 = target + width * 4; + + const XMVECTOR* urow2 = urow0 + 1; + const XMVECTOR* urow3 = urow1 + 1; + const XMVECTOR* vrow2 = vrow0 + 1; + const XMVECTOR* vrow3 = vrow1 + 1; + + // Resize base image to each target mip level + for (size_t level = 1; level < levels; ++level) + { + if (height <= 1) { - size_t slicea = std::min( slice * 2, depth-1 ); - size_t sliceb = std::min( slicea + 1, depth-1 ); + urow1 = urow0; + vrow1 = vrow0; + } - const Image* srca = mipChain.GetImage( level-1, 0, slicea ); - const Image* srcb = mipChain.GetImage( level-1, 0, sliceb ); - const Image* dest = mipChain.GetImage( level, 0, slice ); + if (width <= 1) + { + urow2 = urow0; + urow3 = urow1; + vrow2 = vrow0; + vrow3 = vrow1; + } - if ( !srca || !srcb || !dest ) + if (depth > 1) + { + // 3D box filter + size_t ndepth = depth >> 1; + + for (size_t slice = 0; slice < ndepth; ++slice) + { + size_t slicea = std::min(slice * 2, depth - 1); + size_t sliceb = std::min(slicea + 1, depth - 1); + + const Image* srca = mipChain.GetImage(level - 1, 0, slicea); + const Image* srcb = mipChain.GetImage(level - 1, 0, sliceb); + const Image* dest = mipChain.GetImage(level, 0, slice); + + if (!srca || !srcb || !dest) + return E_POINTER; + + const uint8_t* pSrc1 = srca->pixels; + const uint8_t* pSrc2 = srcb->pixels; + uint8_t* pDest = dest->pixels; + + size_t aRowPitch = srca->rowPitch; + size_t bRowPitch = srcb->rowPitch; + + size_t nwidth = (width > 1) ? (width >> 1) : 1; + size_t nheight = (height > 1) ? (height >> 1) : 1; + + for (size_t y = 0; y < nheight; ++y) + { + if (!_LoadScanlineLinear(urow0, width, pSrc1, aRowPitch, srca->format, filter)) + return E_FAIL; + pSrc1 += aRowPitch; + + if (urow0 != urow1) + { + if (!_LoadScanlineLinear(urow1, width, pSrc1, aRowPitch, srca->format, filter)) + return E_FAIL; + pSrc1 += aRowPitch; + } + + if (!_LoadScanlineLinear(vrow0, width, pSrc2, bRowPitch, srcb->format, filter)) + return E_FAIL; + pSrc2 += bRowPitch; + + if (vrow0 != vrow1) + { + if (!_LoadScanlineLinear(vrow1, width, pSrc2, bRowPitch, srcb->format, filter)) + return E_FAIL; + pSrc2 += bRowPitch; + } + + for (size_t x = 0; x < nwidth; ++x) + { + size_t x2 = x << 1; + + AVERAGE8(target[x], urow0[x2], urow1[x2], urow2[x2], urow3[x2], + vrow0[x2], vrow1[x2], vrow2[x2], vrow3[x2]); + } + + if (!_StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter)) + return E_FAIL; + pDest += dest->rowPitch; + } + } + } + else + { + // 2D box filter + const Image* src = mipChain.GetImage(level - 1, 0, 0); + const Image* dest = mipChain.GetImage(level, 0, 0); + + if (!src || !dest) return E_POINTER; - const uint8_t* pSrc1 = srca->pixels; - const uint8_t* pSrc2 = srcb->pixels; + const uint8_t* pSrc = src->pixels; uint8_t* pDest = dest->pixels; - size_t aRowPitch = srca->rowPitch; - size_t bRowPitch = srcb->rowPitch; + size_t rowPitch = src->rowPitch; size_t nwidth = (width > 1) ? (width >> 1) : 1; size_t nheight = (height > 1) ? (height >> 1) : 1; - for( size_t y = 0; y < nheight; ++y ) + for (size_t y = 0; y < nheight; ++y) { - if ( !_LoadScanlineLinear( urow0, width, pSrc1, aRowPitch, srca->format, filter ) ) + if (!_LoadScanlineLinear(urow0, width, pSrc, rowPitch, src->format, filter)) return E_FAIL; - pSrc1 += aRowPitch; + pSrc += rowPitch; - if ( urow0 != urow1 ) + if (urow0 != urow1) { - if ( !_LoadScanlineLinear( urow1, width, pSrc1, aRowPitch, srca->format, filter ) ) + if (!_LoadScanlineLinear(urow1, width, pSrc, rowPitch, src->format, filter)) return E_FAIL; - pSrc1 += aRowPitch; + pSrc += rowPitch; } - if ( !_LoadScanlineLinear( vrow0, width, pSrc2, bRowPitch, srcb->format, filter ) ) - return E_FAIL; - pSrc2 += bRowPitch; - - if ( vrow0 != vrow1 ) - { - if ( !_LoadScanlineLinear( vrow1, width, pSrc2, bRowPitch, srcb->format, filter ) ) - return E_FAIL; - pSrc2 += bRowPitch; - } - - for( size_t x = 0; x < nwidth; ++x ) + for (size_t x = 0; x < nwidth; ++x) { size_t x2 = x << 1; - AVERAGE8( target[x], urow0[ x2 ], urow1[ x2 ], urow2[ x2 ], urow3[ x2 ], - vrow0[ x2 ], vrow1[ x2 ], vrow2[ x2 ], vrow3[ x2 ] ); + AVERAGE4(target[x], urow0[x2], urow1[x2], urow2[x2], urow3[x2]); } - if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) ) + if (!_StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter)) return E_FAIL; pDest += dest->rowPitch; } } - } - else - { - // 2D box filter - const Image* src = mipChain.GetImage( level-1, 0, 0 ); - const Image* dest = mipChain.GetImage( level, 0, 0 ); - if ( !src || !dest ) - return E_POINTER; + if (height > 1) + height >>= 1; - const uint8_t* pSrc = src->pixels; - uint8_t* pDest = dest->pixels; + if (width > 1) + width >>= 1; - size_t rowPitch = src->rowPitch; - - size_t nwidth = (width > 1) ? (width >> 1) : 1; - size_t nheight = (height > 1) ? (height >> 1) : 1; - - for( size_t y = 0; y < nheight; ++y ) - { - if ( !_LoadScanlineLinear( urow0, width, pSrc, rowPitch, src->format, filter ) ) - return E_FAIL; - pSrc += rowPitch; - - if ( urow0 != urow1 ) - { - if ( !_LoadScanlineLinear( urow1, width, pSrc, rowPitch, src->format, filter ) ) - return E_FAIL; - pSrc += rowPitch; - } - - for( size_t x = 0; x < nwidth; ++x ) - { - size_t x2 = x << 1; - - AVERAGE4( target[ x ], urow0[ x2 ], urow1[ x2 ], urow2[ x2 ], urow3[ x2 ] ); - } - - if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) ) - return E_FAIL; - pDest += dest->rowPitch; - } + if (depth > 1) + depth >>= 1; } - if ( height > 1 ) - height >>= 1; - - if ( width > 1 ) - width >>= 1; - - if ( depth > 1 ) - depth >>= 1; + return S_OK; } - return S_OK; -} - -//--- 3D Linear Filter --- -static HRESULT _Generate3DMipsLinearFilter( _In_ size_t depth, _In_ size_t levels, _In_ DWORD filter, _In_ const ScratchImage& mipChain ) -{ - if ( !depth || !mipChain.GetImages() ) - return E_INVALIDARG; - - // This assumes that the base images are already placed into the mipChain at the top level... (see _Setup3DMips) - - assert( levels > 1 ); - - size_t width = mipChain.GetMetadata().width; - size_t height = mipChain.GetMetadata().height; - - // Allocate temporary space (5 scanlines, plus X/Y/Z filters) - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( (sizeof(XMVECTOR)*width*5), 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - std::unique_ptr lf( new (std::nothrow) LinearFilter[ width+height+depth ] ); - if ( !lf ) - return E_OUTOFMEMORY; - - LinearFilter* lfX = lf.get(); - LinearFilter* lfY = lf.get() + width; - LinearFilter* lfZ = lf.get() + width + height; - - XMVECTOR* target = scanline.get(); - - XMVECTOR* urow0 = target + width; - XMVECTOR* urow1 = target + width*2; - XMVECTOR* vrow0 = target + width*3; - XMVECTOR* vrow1 = target + width*4; - - // Resize base image to each target mip level - for( size_t level=1; level < levels; ++level ) + //--- 3D Linear Filter --- + HRESULT Generate3DMipsLinearFilter(size_t depth, size_t levels, DWORD filter, const ScratchImage& mipChain) { - size_t nwidth = (width > 1) ? (width >> 1) : 1; - _CreateLinearFilter( width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, lfX ); + if (!depth || !mipChain.GetImages()) + return E_INVALIDARG; - size_t nheight = (height > 1) ? (height >> 1) : 1; - _CreateLinearFilter( height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, lfY ); + // This assumes that the base images are already placed into the mipChain at the top level... (see _Setup3DMips) + + assert(levels > 1); + + size_t width = mipChain.GetMetadata().width; + size_t height = mipChain.GetMetadata().height; + + // Allocate temporary space (5 scanlines, plus X/Y/Z filters) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc((sizeof(XMVECTOR)*width * 5), 16))); + if (!scanline) + return E_OUTOFMEMORY; + + std::unique_ptr lf(new (std::nothrow) LinearFilter[width + height + depth]); + if (!lf) + return E_OUTOFMEMORY; + + LinearFilter* lfX = lf.get(); + LinearFilter* lfY = lf.get() + width; + LinearFilter* lfZ = lf.get() + width + height; + + XMVECTOR* target = scanline.get(); + + XMVECTOR* urow0 = target + width; + XMVECTOR* urow1 = target + width * 2; + XMVECTOR* vrow0 = target + width * 3; + XMVECTOR* vrow1 = target + width * 4; + + // Resize base image to each target mip level + for (size_t level = 1; level < levels; ++level) + { + size_t nwidth = (width > 1) ? (width >> 1) : 1; + _CreateLinearFilter(width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, lfX); + + size_t nheight = (height > 1) ? (height >> 1) : 1; + _CreateLinearFilter(height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, lfY); #ifdef _DEBUG - memset( urow0, 0xCD, sizeof(XMVECTOR)*width ); - memset( urow1, 0xDD, sizeof(XMVECTOR)*width ); - memset( vrow0, 0xED, sizeof(XMVECTOR)*width ); - memset( vrow1, 0xFD, sizeof(XMVECTOR)*width ); + memset(urow0, 0xCD, sizeof(XMVECTOR)*width); + memset(urow1, 0xDD, sizeof(XMVECTOR)*width); + memset(vrow0, 0xED, sizeof(XMVECTOR)*width); + memset(vrow1, 0xFD, sizeof(XMVECTOR)*width); #endif - if ( depth > 1 ) - { - // 3D linear filter - size_t ndepth = depth >> 1; - _CreateLinearFilter( depth, ndepth, (filter & TEX_FILTER_WRAP_W) != 0, lfZ ); - - for( size_t slice=0; slice < ndepth; ++slice ) + if (depth > 1) { - auto& toZ = lfZ[ slice ]; + // 3D linear filter + size_t ndepth = depth >> 1; + _CreateLinearFilter(depth, ndepth, (filter & TEX_FILTER_WRAP_W) != 0, lfZ); - const Image* srca = mipChain.GetImage( level-1, 0, toZ.u0 ); - const Image* srcb = mipChain.GetImage( level-1, 0, toZ.u1 ); - if ( !srca || !srcb ) + for (size_t slice = 0; slice < ndepth; ++slice) + { + auto& toZ = lfZ[slice]; + + const Image* srca = mipChain.GetImage(level - 1, 0, toZ.u0); + const Image* srcb = mipChain.GetImage(level - 1, 0, toZ.u1); + if (!srca || !srcb) + return E_POINTER; + + size_t u0 = size_t(-1); + size_t u1 = size_t(-1); + + const Image* dest = mipChain.GetImage(level, 0, slice); + if (!dest) + return E_POINTER; + + uint8_t* pDest = dest->pixels; + + for (size_t y = 0; y < nheight; ++y) + { + auto& toY = lfY[y]; + + if (toY.u0 != u0) + { + if (toY.u0 != u1) + { + u0 = toY.u0; + + if (!_LoadScanlineLinear(urow0, width, srca->pixels + (srca->rowPitch * u0), srca->rowPitch, srca->format, filter) + || !_LoadScanlineLinear(vrow0, width, srcb->pixels + (srcb->rowPitch * u0), srcb->rowPitch, srcb->format, filter)) + return E_FAIL; + } + else + { + u0 = u1; + u1 = size_t(-1); + + std::swap(urow0, urow1); + std::swap(vrow0, vrow1); + } + } + + if (toY.u1 != u1) + { + u1 = toY.u1; + + if (!_LoadScanlineLinear(urow1, width, srca->pixels + (srca->rowPitch * u1), srca->rowPitch, srca->format, filter) + || !_LoadScanlineLinear(vrow1, width, srcb->pixels + (srcb->rowPitch * u1), srcb->rowPitch, srcb->format, filter)) + return E_FAIL; + } + + for (size_t x = 0; x < nwidth; ++x) + { + auto& toX = lfX[x]; + + TRILINEAR_INTERPOLATE(target[x], toX, toY, toZ, urow0, urow1, vrow0, vrow1); + } + + if (!_StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter)) + return E_FAIL; + pDest += dest->rowPitch; + } + } + } + else + { + // 2D linear filter + const Image* src = mipChain.GetImage(level - 1, 0, 0); + const Image* dest = mipChain.GetImage(level, 0, 0); + + if (!src || !dest) return E_POINTER; + const uint8_t* pSrc = src->pixels; + uint8_t* pDest = dest->pixels; + + size_t rowPitch = src->rowPitch; + size_t u0 = size_t(-1); size_t u1 = size_t(-1); - const Image* dest = mipChain.GetImage( level, 0, slice ); - if ( !dest ) - return E_POINTER; - - uint8_t* pDest = dest->pixels; - - for( size_t y = 0; y < nheight; ++y ) + for (size_t y = 0; y < nheight; ++y) { - auto& toY = lfY[ y ]; + auto& toY = lfY[y]; - if ( toY.u0 != u0 ) + if (toY.u0 != u0) { - if ( toY.u0 != u1 ) + if (toY.u0 != u1) { u0 = toY.u0; - if ( !_LoadScanlineLinear( urow0, width, srca->pixels + (srca->rowPitch * u0), srca->rowPitch, srca->format, filter ) - || !_LoadScanlineLinear( vrow0, width, srcb->pixels + (srcb->rowPitch * u0), srcb->rowPitch, srcb->format, filter ) ) + if (!_LoadScanlineLinear(urow0, width, pSrc + (rowPitch * u0), rowPitch, src->format, filter)) return E_FAIL; } else @@ -1780,291 +1858,371 @@ static HRESULT _Generate3DMipsLinearFilter( _In_ size_t depth, _In_ size_t level u0 = u1; u1 = size_t(-1); - std::swap( urow0, urow1 ); - std::swap( vrow0, vrow1 ); + std::swap(urow0, urow1); } } - if ( toY.u1 != u1 ) + if (toY.u1 != u1) { u1 = toY.u1; - if ( !_LoadScanlineLinear( urow1, width, srca->pixels + (srca->rowPitch * u1), srca->rowPitch, srca->format, filter ) - || !_LoadScanlineLinear( vrow1, width, srcb->pixels + (srcb->rowPitch * u1), srcb->rowPitch, srcb->format, filter ) ) + if (!_LoadScanlineLinear(urow1, width, pSrc + (rowPitch * u1), rowPitch, src->format, filter)) return E_FAIL; } - for( size_t x = 0; x < nwidth; ++x ) + for (size_t x = 0; x < nwidth; ++x) { - auto& toX = lfX[ x ]; + auto& toX = lfX[x]; - TRILINEAR_INTERPOLATE( target[x], toX, toY, toZ, urow0, urow1, vrow0, vrow1 ); + BILINEAR_INTERPOLATE(target[x], toX, toY, urow0, urow1); } - if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) ) + if (!_StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter)) return E_FAIL; pDest += dest->rowPitch; } } + + if (height > 1) + height >>= 1; + + if (width > 1) + width >>= 1; + + if (depth > 1) + depth >>= 1; } - else + + return S_OK; + } + + + //--- 3D Cubic Filter --- + HRESULT Generate3DMipsCubicFilter(size_t depth, size_t levels, DWORD filter, const ScratchImage& mipChain) + { + if (!depth || !mipChain.GetImages()) + return E_INVALIDARG; + + // This assumes that the base images are already placed into the mipChain at the top level... (see _Setup3DMips) + + assert(levels > 1); + + size_t width = mipChain.GetMetadata().width; + size_t height = mipChain.GetMetadata().height; + + // Allocate temporary space (17 scanlines, plus X/Y/Z filters) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc((sizeof(XMVECTOR)*width * 17), 16))); + if (!scanline) + return E_OUTOFMEMORY; + + std::unique_ptr cf(new (std::nothrow) CubicFilter[width + height + depth]); + if (!cf) + return E_OUTOFMEMORY; + + CubicFilter* cfX = cf.get(); + CubicFilter* cfY = cf.get() + width; + CubicFilter* cfZ = cf.get() + width + height; + + XMVECTOR* target = scanline.get(); + + XMVECTOR* urow[4]; + XMVECTOR* vrow[4]; + XMVECTOR* srow[4]; + XMVECTOR* trow[4]; + + XMVECTOR *ptr = scanline.get() + width; + for (size_t j = 0; j < 4; ++j) { - // 2D linear filter - const Image* src = mipChain.GetImage( level-1, 0, 0 ); - const Image* dest = mipChain.GetImage( level, 0, 0 ); - - if ( !src || !dest ) - return E_POINTER; - - const uint8_t* pSrc = src->pixels; - uint8_t* pDest = dest->pixels; - - size_t rowPitch = src->rowPitch; - - size_t u0 = size_t(-1); - size_t u1 = size_t(-1); - - for( size_t y = 0; y < nheight; ++y ) - { - auto& toY = lfY[ y ]; - - if ( toY.u0 != u0 ) - { - if ( toY.u0 != u1 ) - { - u0 = toY.u0; - - if ( !_LoadScanlineLinear( urow0, width, pSrc + (rowPitch * u0), rowPitch, src->format, filter ) ) - return E_FAIL; - } - else - { - u0 = u1; - u1 = size_t(-1); - - std::swap( urow0, urow1 ); - } - } - - if ( toY.u1 != u1 ) - { - u1 = toY.u1; - - if ( !_LoadScanlineLinear( urow1, width, pSrc + (rowPitch * u1), rowPitch, src->format, filter ) ) - return E_FAIL; - } - - for( size_t x = 0; x < nwidth; ++x ) - { - auto& toX = lfX[ x ]; - - BILINEAR_INTERPOLATE( target[x], toX, toY, urow0, urow1 ); - } - - if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) ) - return E_FAIL; - pDest += dest->rowPitch; - } + urow[j] = ptr; ptr += width; + vrow[j] = ptr; ptr += width; + srow[j] = ptr; ptr += width; + trow[j] = ptr; ptr += width; } - if ( height > 1 ) - height >>= 1; + // Resize base image to each target mip level + for (size_t level = 1; level < levels; ++level) + { + size_t nwidth = (width > 1) ? (width >> 1) : 1; + _CreateCubicFilter(width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, (filter & TEX_FILTER_MIRROR_U) != 0, cfX); - if ( width > 1 ) - width >>= 1; - - if ( depth > 1 ) - depth >>= 1; - } - - return S_OK; -} - - -//--- 3D Cubic Filter --- -static HRESULT _Generate3DMipsCubicFilter( _In_ size_t depth, _In_ size_t levels, _In_ DWORD filter, _In_ const ScratchImage& mipChain ) -{ - if ( !depth || !mipChain.GetImages() ) - return E_INVALIDARG; - - // This assumes that the base images are already placed into the mipChain at the top level... (see _Setup3DMips) - - assert( levels > 1 ); - - size_t width = mipChain.GetMetadata().width; - size_t height = mipChain.GetMetadata().height; - - // Allocate temporary space (17 scanlines, plus X/Y/Z filters) - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( (sizeof(XMVECTOR)*width*17), 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - std::unique_ptr cf( new (std::nothrow) CubicFilter[ width+height+depth ] ); - if ( !cf ) - return E_OUTOFMEMORY; - - CubicFilter* cfX = cf.get(); - CubicFilter* cfY = cf.get() + width; - CubicFilter* cfZ = cf.get() + width + height; - - XMVECTOR* target = scanline.get(); - - XMVECTOR* urow[4]; - XMVECTOR* vrow[4]; - XMVECTOR* srow[4]; - XMVECTOR* trow[4]; - - XMVECTOR *ptr = scanline.get() + width; - for( size_t j = 0; j < 4; ++j ) - { - urow[j] = ptr; ptr += width; - vrow[j] = ptr; ptr += width; - srow[j] = ptr; ptr += width; - trow[j] = ptr; ptr += width; - } - - // Resize base image to each target mip level - for( size_t level=1; level < levels; ++level ) - { - size_t nwidth = (width > 1) ? (width >> 1) : 1; - _CreateCubicFilter( width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, (filter & TEX_FILTER_MIRROR_U) != 0, cfX ); - - size_t nheight = (height > 1) ? (height >> 1) : 1; - _CreateCubicFilter( height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, (filter & TEX_FILTER_MIRROR_V) != 0, cfY ); + size_t nheight = (height > 1) ? (height >> 1) : 1; + _CreateCubicFilter(height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, (filter & TEX_FILTER_MIRROR_V) != 0, cfY); #ifdef _DEBUG - for( size_t j = 0; j < 4; ++j ) - { - memset( urow[j], 0xCD, sizeof(XMVECTOR)*width ); - memset( vrow[j], 0xDD, sizeof(XMVECTOR)*width ); - memset( srow[j], 0xED, sizeof(XMVECTOR)*width ); - memset( trow[j], 0xFD, sizeof(XMVECTOR)*width ); - } + for (size_t j = 0; j < 4; ++j) + { + memset(urow[j], 0xCD, sizeof(XMVECTOR)*width); + memset(vrow[j], 0xDD, sizeof(XMVECTOR)*width); + memset(srow[j], 0xED, sizeof(XMVECTOR)*width); + memset(trow[j], 0xFD, sizeof(XMVECTOR)*width); + } #endif - if ( depth > 1 ) - { - // 3D cubic filter - size_t ndepth = depth >> 1; - _CreateCubicFilter( depth, ndepth, (filter & TEX_FILTER_WRAP_W) != 0, (filter & TEX_FILTER_MIRROR_W) != 0, cfZ ); - - for( size_t slice=0; slice < ndepth; ++slice ) + if (depth > 1) { - auto& toZ = cfZ[ slice ]; + // 3D cubic filter + size_t ndepth = depth >> 1; + _CreateCubicFilter(depth, ndepth, (filter & TEX_FILTER_WRAP_W) != 0, (filter & TEX_FILTER_MIRROR_W) != 0, cfZ); - const Image* srca = mipChain.GetImage( level-1, 0, toZ.u0 ); - const Image* srcb = mipChain.GetImage( level-1, 0, toZ.u1 ); - const Image* srcc = mipChain.GetImage( level-1, 0, toZ.u2 ); - const Image* srcd = mipChain.GetImage( level-1, 0, toZ.u3 ); - if ( !srca || !srcb || !srcc || !srcd ) + for (size_t slice = 0; slice < ndepth; ++slice) + { + auto& toZ = cfZ[slice]; + + const Image* srca = mipChain.GetImage(level - 1, 0, toZ.u0); + const Image* srcb = mipChain.GetImage(level - 1, 0, toZ.u1); + const Image* srcc = mipChain.GetImage(level - 1, 0, toZ.u2); + const Image* srcd = mipChain.GetImage(level - 1, 0, toZ.u3); + if (!srca || !srcb || !srcc || !srcd) + return E_POINTER; + + size_t u0 = size_t(-1); + size_t u1 = size_t(-1); + size_t u2 = size_t(-1); + size_t u3 = size_t(-1); + + const Image* dest = mipChain.GetImage(level, 0, slice); + if (!dest) + return E_POINTER; + + uint8_t* pDest = dest->pixels; + + for (size_t y = 0; y < nheight; ++y) + { + auto& toY = cfY[y]; + + // Scanline 1 + if (toY.u0 != u0) + { + if (toY.u0 != u1 && toY.u0 != u2 && toY.u0 != u3) + { + u0 = toY.u0; + + if (!_LoadScanlineLinear(urow[0], width, srca->pixels + (srca->rowPitch * u0), srca->rowPitch, srca->format, filter) + || !_LoadScanlineLinear(urow[1], width, srcb->pixels + (srcb->rowPitch * u0), srcb->rowPitch, srcb->format, filter) + || !_LoadScanlineLinear(urow[2], width, srcc->pixels + (srcc->rowPitch * u0), srcc->rowPitch, srcc->format, filter) + || !_LoadScanlineLinear(urow[3], width, srcd->pixels + (srcd->rowPitch * u0), srcd->rowPitch, srcd->format, filter)) + return E_FAIL; + } + else if (toY.u0 == u1) + { + u0 = u1; + u1 = size_t(-1); + + std::swap(urow[0], vrow[0]); + std::swap(urow[1], vrow[1]); + std::swap(urow[2], vrow[2]); + std::swap(urow[3], vrow[3]); + } + else if (toY.u0 == u2) + { + u0 = u2; + u2 = size_t(-1); + + std::swap(urow[0], srow[0]); + std::swap(urow[1], srow[1]); + std::swap(urow[2], srow[2]); + std::swap(urow[3], srow[3]); + } + else if (toY.u0 == u3) + { + u0 = u3; + u3 = size_t(-1); + + std::swap(urow[0], trow[0]); + std::swap(urow[1], trow[1]); + std::swap(urow[2], trow[2]); + std::swap(urow[3], trow[3]); + } + } + + // Scanline 2 + if (toY.u1 != u1) + { + if (toY.u1 != u2 && toY.u1 != u3) + { + u1 = toY.u1; + + if (!_LoadScanlineLinear(vrow[0], width, srca->pixels + (srca->rowPitch * u1), srca->rowPitch, srca->format, filter) + || !_LoadScanlineLinear(vrow[1], width, srcb->pixels + (srcb->rowPitch * u1), srcb->rowPitch, srcb->format, filter) + || !_LoadScanlineLinear(vrow[2], width, srcc->pixels + (srcc->rowPitch * u1), srcc->rowPitch, srcc->format, filter) + || !_LoadScanlineLinear(vrow[3], width, srcd->pixels + (srcd->rowPitch * u1), srcd->rowPitch, srcd->format, filter)) + return E_FAIL; + } + else if (toY.u1 == u2) + { + u1 = u2; + u2 = size_t(-1); + + std::swap(vrow[0], srow[0]); + std::swap(vrow[1], srow[1]); + std::swap(vrow[2], srow[2]); + std::swap(vrow[3], srow[3]); + } + else if (toY.u1 == u3) + { + u1 = u3; + u3 = size_t(-1); + + std::swap(vrow[0], trow[0]); + std::swap(vrow[1], trow[1]); + std::swap(vrow[2], trow[2]); + std::swap(vrow[3], trow[3]); + } + } + + // Scanline 3 + if (toY.u2 != u2) + { + if (toY.u2 != u3) + { + u2 = toY.u2; + + if (!_LoadScanlineLinear(srow[0], width, srca->pixels + (srca->rowPitch * u2), srca->rowPitch, srca->format, filter) + || !_LoadScanlineLinear(srow[1], width, srcb->pixels + (srcb->rowPitch * u2), srcb->rowPitch, srcb->format, filter) + || !_LoadScanlineLinear(srow[2], width, srcc->pixels + (srcc->rowPitch * u2), srcc->rowPitch, srcc->format, filter) + || !_LoadScanlineLinear(srow[3], width, srcd->pixels + (srcd->rowPitch * u2), srcd->rowPitch, srcd->format, filter)) + return E_FAIL; + } + else + { + u2 = u3; + u3 = size_t(-1); + + std::swap(srow[0], trow[0]); + std::swap(srow[1], trow[1]); + std::swap(srow[2], trow[2]); + std::swap(srow[3], trow[3]); + } + } + + // Scanline 4 + if (toY.u3 != u3) + { + u3 = toY.u3; + + if (!_LoadScanlineLinear(trow[0], width, srca->pixels + (srca->rowPitch * u3), srca->rowPitch, srca->format, filter) + || !_LoadScanlineLinear(trow[1], width, srcb->pixels + (srcb->rowPitch * u3), srcb->rowPitch, srcb->format, filter) + || !_LoadScanlineLinear(trow[2], width, srcc->pixels + (srcc->rowPitch * u3), srcc->rowPitch, srcc->format, filter) + || !_LoadScanlineLinear(trow[3], width, srcd->pixels + (srcd->rowPitch * u3), srcd->rowPitch, srcd->format, filter)) + return E_FAIL; + } + + for (size_t x = 0; x < nwidth; ++x) + { + auto& toX = cfX[x]; + + XMVECTOR D[4]; + + for (size_t j = 0; j < 4; ++j) + { + XMVECTOR C0, C1, C2, C3; + CUBIC_INTERPOLATE(C0, toX.x, urow[j][toX.u0], urow[j][toX.u1], urow[j][toX.u2], urow[j][toX.u3]); + CUBIC_INTERPOLATE(C1, toX.x, vrow[j][toX.u0], vrow[j][toX.u1], vrow[j][toX.u2], vrow[j][toX.u3]); + CUBIC_INTERPOLATE(C2, toX.x, srow[j][toX.u0], srow[j][toX.u1], srow[j][toX.u2], srow[j][toX.u3]); + CUBIC_INTERPOLATE(C3, toX.x, trow[j][toX.u0], trow[j][toX.u1], trow[j][toX.u2], trow[j][toX.u3]); + + CUBIC_INTERPOLATE(D[j], toY.x, C0, C1, C2, C3); + } + + CUBIC_INTERPOLATE(target[x], toZ.x, D[0], D[1], D[2], D[3]); + } + + if (!_StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter)) + return E_FAIL; + pDest += dest->rowPitch; + } + } + } + else + { + // 2D cubic filter + const Image* src = mipChain.GetImage(level - 1, 0, 0); + const Image* dest = mipChain.GetImage(level, 0, 0); + + if (!src || !dest) return E_POINTER; + const uint8_t* pSrc = src->pixels; + uint8_t* pDest = dest->pixels; + + size_t rowPitch = src->rowPitch; + size_t u0 = size_t(-1); size_t u1 = size_t(-1); size_t u2 = size_t(-1); size_t u3 = size_t(-1); - const Image* dest = mipChain.GetImage( level, 0, slice ); - if ( !dest ) - return E_POINTER; - - uint8_t* pDest = dest->pixels; - - for( size_t y = 0; y < nheight; ++y ) + for (size_t y = 0; y < nheight; ++y) { - auto& toY = cfY[ y ]; + auto& toY = cfY[y]; // Scanline 1 - if ( toY.u0 != u0 ) + if (toY.u0 != u0) { - if ( toY.u0 != u1 && toY.u0 != u2 && toY.u0 != u3 ) + if (toY.u0 != u1 && toY.u0 != u2 && toY.u0 != u3) { u0 = toY.u0; - if ( !_LoadScanlineLinear( urow[0], width, srca->pixels + (srca->rowPitch * u0), srca->rowPitch, srca->format, filter ) - || !_LoadScanlineLinear( urow[1], width, srcb->pixels + (srcb->rowPitch * u0), srcb->rowPitch, srcb->format, filter ) - || !_LoadScanlineLinear( urow[2], width, srcc->pixels + (srcc->rowPitch * u0), srcc->rowPitch, srcc->format, filter ) - || !_LoadScanlineLinear( urow[3], width, srcd->pixels + (srcd->rowPitch * u0), srcd->rowPitch, srcd->format, filter ) ) + if (!_LoadScanlineLinear(urow[0], width, pSrc + (rowPitch * u0), rowPitch, src->format, filter)) return E_FAIL; } - else if ( toY.u0 == u1 ) + else if (toY.u0 == u1) { u0 = u1; u1 = size_t(-1); - std::swap( urow[0], vrow[0] ); - std::swap( urow[1], vrow[1] ); - std::swap( urow[2], vrow[2] ); - std::swap( urow[3], vrow[3] ); + std::swap(urow[0], vrow[0]); } - else if ( toY.u0 == u2 ) + else if (toY.u0 == u2) { u0 = u2; u2 = size_t(-1); - std::swap( urow[0], srow[0] ); - std::swap( urow[1], srow[1] ); - std::swap( urow[2], srow[2] ); - std::swap( urow[3], srow[3] ); + std::swap(urow[0], srow[0]); } - else if ( toY.u0 == u3 ) + else if (toY.u0 == u3) { u0 = u3; u3 = size_t(-1); - std::swap( urow[0], trow[0] ); - std::swap( urow[1], trow[1] ); - std::swap( urow[2], trow[2] ); - std::swap( urow[3], trow[3] ); + std::swap(urow[0], trow[0]); } } // Scanline 2 - if ( toY.u1 != u1 ) + if (toY.u1 != u1) { - if ( toY.u1 != u2 && toY.u1 != u3 ) + if (toY.u1 != u2 && toY.u1 != u3) { u1 = toY.u1; - if ( !_LoadScanlineLinear( vrow[0], width, srca->pixels + (srca->rowPitch * u1), srca->rowPitch, srca->format, filter ) - || !_LoadScanlineLinear( vrow[1], width, srcb->pixels + (srcb->rowPitch * u1), srcb->rowPitch, srcb->format, filter ) - || !_LoadScanlineLinear( vrow[2], width, srcc->pixels + (srcc->rowPitch * u1), srcc->rowPitch, srcc->format, filter ) - || !_LoadScanlineLinear( vrow[3], width, srcd->pixels + (srcd->rowPitch * u1), srcd->rowPitch, srcd->format, filter ) ) + if (!_LoadScanlineLinear(vrow[0], width, pSrc + (rowPitch * u1), rowPitch, src->format, filter)) return E_FAIL; } - else if ( toY.u1 == u2 ) + else if (toY.u1 == u2) { u1 = u2; u2 = size_t(-1); - std::swap( vrow[0], srow[0] ); - std::swap( vrow[1], srow[1] ); - std::swap( vrow[2], srow[2] ); - std::swap( vrow[3], srow[3] ); + std::swap(vrow[0], srow[0]); } - else if ( toY.u1 == u3 ) + else if (toY.u1 == u3) { u1 = u3; u3 = size_t(-1); - std::swap( vrow[0], trow[0] ); - std::swap( vrow[1], trow[1] ); - std::swap( vrow[2], trow[2] ); - std::swap( vrow[3], trow[3] ); + std::swap(vrow[0], trow[0]); } } // Scanline 3 - if ( toY.u2 != u2 ) + if (toY.u2 != u2) { - if ( toY.u2 != u3 ) + if (toY.u2 != u3) { u2 = toY.u2; - if ( !_LoadScanlineLinear( srow[0], width, srca->pixels + (srca->rowPitch * u2), srca->rowPitch, srca->format, filter ) - || !_LoadScanlineLinear( srow[1], width, srcb->pixels + (srcb->rowPitch * u2), srcb->rowPitch, srcb->format, filter ) - || !_LoadScanlineLinear( srow[2], width, srcc->pixels + (srcc->rowPitch * u2), srcc->rowPitch, srcc->format, filter ) - || !_LoadScanlineLinear( srow[3], width, srcd->pixels + (srcd->rowPitch * u2), srcd->rowPitch, srcd->format, filter ) ) + if (!_LoadScanlineLinear(srow[0], width, pSrc + (rowPitch * u2), rowPitch, src->format, filter)) return E_FAIL; } else @@ -2072,431 +2230,290 @@ static HRESULT _Generate3DMipsCubicFilter( _In_ size_t depth, _In_ size_t levels u2 = u3; u3 = size_t(-1); - std::swap( srow[0], trow[0] ); - std::swap( srow[1], trow[1] ); - std::swap( srow[2], trow[2] ); - std::swap( srow[3], trow[3] ); + std::swap(srow[0], trow[0]); } } // Scanline 4 - if ( toY.u3 != u3 ) + if (toY.u3 != u3) { u3 = toY.u3; - if ( !_LoadScanlineLinear( trow[0], width, srca->pixels + (srca->rowPitch * u3), srca->rowPitch, srca->format, filter ) - || !_LoadScanlineLinear( trow[1], width, srcb->pixels + (srcb->rowPitch * u3), srcb->rowPitch, srcb->format, filter ) - || !_LoadScanlineLinear( trow[2], width, srcc->pixels + (srcc->rowPitch * u3), srcc->rowPitch, srcc->format, filter ) - || !_LoadScanlineLinear( trow[3], width, srcd->pixels + (srcd->rowPitch * u3), srcd->rowPitch, srcd->format, filter ) ) + if (!_LoadScanlineLinear(trow[0], width, pSrc + (rowPitch * u3), rowPitch, src->format, filter)) return E_FAIL; } - for( size_t x = 0; x < nwidth; ++x ) + for (size_t x = 0; x < nwidth; ++x) { - auto& toX = cfX[ x ]; + auto& toX = cfX[x]; - XMVECTOR D[4]; + XMVECTOR C0, C1, C2, C3; + CUBIC_INTERPOLATE(C0, toX.x, urow[0][toX.u0], urow[0][toX.u1], urow[0][toX.u2], urow[0][toX.u3]); + CUBIC_INTERPOLATE(C1, toX.x, vrow[0][toX.u0], vrow[0][toX.u1], vrow[0][toX.u2], vrow[0][toX.u3]); + CUBIC_INTERPOLATE(C2, toX.x, srow[0][toX.u0], srow[0][toX.u1], srow[0][toX.u2], srow[0][toX.u3]); + CUBIC_INTERPOLATE(C3, toX.x, trow[0][toX.u0], trow[0][toX.u1], trow[0][toX.u2], trow[0][toX.u3]); - for( size_t j=0; j < 4; ++j ) - { - XMVECTOR C0, C1, C2, C3; - CUBIC_INTERPOLATE( C0, toX.x, urow[j][ toX.u0 ], urow[j][ toX.u1 ], urow[j][ toX.u2 ], urow[j][ toX.u3 ] ); - CUBIC_INTERPOLATE( C1, toX.x, vrow[j][ toX.u0 ], vrow[j][ toX.u1 ], vrow[j][ toX.u2 ], vrow[j][ toX.u3 ] ); - CUBIC_INTERPOLATE( C2, toX.x, srow[j][ toX.u0 ], srow[j][ toX.u1 ], srow[j][ toX.u2 ], srow[j][ toX.u3 ] ); - CUBIC_INTERPOLATE( C3, toX.x, trow[j][ toX.u0 ], trow[j][ toX.u1 ], trow[j][ toX.u2 ], trow[j][ toX.u3 ] ); - - CUBIC_INTERPOLATE( D[j], toY.x, C0, C1, C2, C3 ); - } - - CUBIC_INTERPOLATE( target[x], toZ.x, D[0], D[1], D[2], D[3] ); + CUBIC_INTERPOLATE(target[x], toY.x, C0, C1, C2, C3); } - if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) ) + if (!_StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter)) return E_FAIL; pDest += dest->rowPitch; } } - } - else - { - // 2D cubic filter - const Image* src = mipChain.GetImage( level-1, 0, 0 ); - const Image* dest = mipChain.GetImage( level, 0, 0 ); - if ( !src || !dest ) - return E_POINTER; + if (height > 1) + height >>= 1; - const uint8_t* pSrc = src->pixels; - uint8_t* pDest = dest->pixels; + if (width > 1) + width >>= 1; - size_t rowPitch = src->rowPitch; - - size_t u0 = size_t(-1); - size_t u1 = size_t(-1); - size_t u2 = size_t(-1); - size_t u3 = size_t(-1); - - for( size_t y = 0; y < nheight; ++y ) - { - auto& toY = cfY[ y ]; - - // Scanline 1 - if ( toY.u0 != u0 ) - { - if ( toY.u0 != u1 && toY.u0 != u2 && toY.u0 != u3 ) - { - u0 = toY.u0; - - if ( !_LoadScanlineLinear( urow[0], width, pSrc + (rowPitch * u0), rowPitch, src->format, filter ) ) - return E_FAIL; - } - else if ( toY.u0 == u1 ) - { - u0 = u1; - u1 = size_t(-1); - - std::swap( urow[0], vrow[0] ); - } - else if ( toY.u0 == u2 ) - { - u0 = u2; - u2 = size_t(-1); - - std::swap( urow[0], srow[0] ); - } - else if ( toY.u0 == u3 ) - { - u0 = u3; - u3 = size_t(-1); - - std::swap( urow[0], trow[0] ); - } - } - - // Scanline 2 - if ( toY.u1 != u1 ) - { - if ( toY.u1 != u2 && toY.u1 != u3 ) - { - u1 = toY.u1; - - if ( !_LoadScanlineLinear( vrow[0], width, pSrc + (rowPitch * u1), rowPitch, src->format, filter ) ) - return E_FAIL; - } - else if ( toY.u1 == u2 ) - { - u1 = u2; - u2 = size_t(-1); - - std::swap( vrow[0], srow[0] ); - } - else if ( toY.u1 == u3 ) - { - u1 = u3; - u3 = size_t(-1); - - std::swap( vrow[0], trow[0] ); - } - } - - // Scanline 3 - if ( toY.u2 != u2 ) - { - if ( toY.u2 != u3 ) - { - u2 = toY.u2; - - if ( !_LoadScanlineLinear( srow[0], width, pSrc + (rowPitch * u2), rowPitch, src->format, filter ) ) - return E_FAIL; - } - else - { - u2 = u3; - u3 = size_t(-1); - - std::swap( srow[0], trow[0] ); - } - } - - // Scanline 4 - if ( toY.u3 != u3 ) - { - u3 = toY.u3; - - if ( !_LoadScanlineLinear( trow[0], width, pSrc + (rowPitch * u3), rowPitch, src->format, filter ) ) - return E_FAIL; - } - - for( size_t x = 0; x < nwidth; ++x ) - { - auto& toX = cfX[ x ]; - - XMVECTOR C0, C1, C2, C3; - CUBIC_INTERPOLATE( C0, toX.x, urow[0][ toX.u0 ], urow[0][ toX.u1 ], urow[0][ toX.u2 ], urow[0][ toX.u3 ] ); - CUBIC_INTERPOLATE( C1, toX.x, vrow[0][ toX.u0 ], vrow[0][ toX.u1 ], vrow[0][ toX.u2 ], vrow[0][ toX.u3 ] ); - CUBIC_INTERPOLATE( C2, toX.x, srow[0][ toX.u0 ], srow[0][ toX.u1 ], srow[0][ toX.u2 ], srow[0][ toX.u3 ] ); - CUBIC_INTERPOLATE( C3, toX.x, trow[0][ toX.u0 ], trow[0][ toX.u1 ], trow[0][ toX.u2 ], trow[0][ toX.u3 ] ); - - CUBIC_INTERPOLATE( target[x], toY.x, C0, C1, C2, C3 ); - } - - if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, target, nwidth, filter ) ) - return E_FAIL; - pDest += dest->rowPitch; - } + if (depth > 1) + depth >>= 1; } - if ( height > 1 ) - height >>= 1; - - if ( width > 1 ) - width >>= 1; - - if ( depth > 1 ) - depth >>= 1; + return S_OK; } - return S_OK; -} - -//--- 3D Triangle Filter --- -static HRESULT _Generate3DMipsTriangleFilter( _In_ size_t depth, _In_ size_t levels, _In_ DWORD filter, _In_ const ScratchImage& mipChain ) -{ - if ( !depth || !mipChain.GetImages() ) - return E_INVALIDARG; - - using namespace TriangleFilter; - - // This assumes that the base images are already placed into the mipChain at the top level... (see _Setup3DMips) - - assert( levels > 1 ); - - size_t width = mipChain.GetMetadata().width; - size_t height = mipChain.GetMetadata().height; - - // Allocate initial temporary space (1 scanline, accumulation rows, plus X/Y/Z filters) - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( sizeof(XMVECTOR) * width, 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - std::unique_ptr sliceActive( new (std::nothrow) TriangleRow[ depth ] ); - if ( !sliceActive ) - return E_OUTOFMEMORY; - - TriangleRow * sliceFree = nullptr; - - std::unique_ptr tfX, tfY, tfZ; - - XMVECTOR* row = scanline.get(); - - // Resize base image to each target mip level - for( size_t level=1; level < levels; ++level ) + //--- 3D Triangle Filter --- + HRESULT Generate3DMipsTriangleFilter(size_t depth, size_t levels, DWORD filter, const ScratchImage& mipChain) { - size_t nwidth = (width > 1) ? (width >> 1) : 1; - HRESULT hr = _Create( width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, tfX ); - if ( FAILED(hr) ) - return hr; + if (!depth || !mipChain.GetImages()) + return E_INVALIDARG; - size_t nheight = (height > 1) ? (height >> 1) : 1; - hr = _Create( height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, tfY ); - if ( FAILED(hr) ) - return hr; + using namespace TriangleFilter; - size_t ndepth = (depth > 1 ) ? (depth >> 1) : 1; - hr = _Create( depth, ndepth, (filter & TEX_FILTER_WRAP_W) != 0, tfZ ); - if ( FAILED(hr) ) - return hr; + // This assumes that the base images are already placed into the mipChain at the top level... (see _Setup3DMips) + + assert(levels > 1); + + size_t width = mipChain.GetMetadata().width; + size_t height = mipChain.GetMetadata().height; + + // Allocate initial temporary space (1 scanline, accumulation rows, plus X/Y/Z filters) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc(sizeof(XMVECTOR) * width, 16))); + if (!scanline) + return E_OUTOFMEMORY; + + std::unique_ptr sliceActive(new (std::nothrow) TriangleRow[depth]); + if (!sliceActive) + return E_OUTOFMEMORY; + + TriangleRow * sliceFree = nullptr; + + std::unique_ptr tfX, tfY, tfZ; + + XMVECTOR* row = scanline.get(); + + // Resize base image to each target mip level + for (size_t level = 1; level < levels; ++level) + { + size_t nwidth = (width > 1) ? (width >> 1) : 1; + HRESULT hr = _Create(width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, tfX); + if (FAILED(hr)) + return hr; + + size_t nheight = (height > 1) ? (height >> 1) : 1; + hr = _Create(height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, tfY); + if (FAILED(hr)) + return hr; + + size_t ndepth = (depth > 1) ? (depth >> 1) : 1; + hr = _Create(depth, ndepth, (filter & TEX_FILTER_WRAP_W) != 0, tfZ); + if (FAILED(hr)) + return hr; #ifdef _DEBUG - memset( row, 0xCD, sizeof(XMVECTOR)*width ); + memset(row, 0xCD, sizeof(XMVECTOR)*width); #endif - auto xFromEnd = reinterpret_cast( reinterpret_cast( tfX.get() ) + tfX->sizeInBytes ); - auto yFromEnd = reinterpret_cast( reinterpret_cast( tfY.get() ) + tfY->sizeInBytes ); - auto zFromEnd = reinterpret_cast( reinterpret_cast( tfZ.get() ) + tfZ->sizeInBytes ); + auto xFromEnd = reinterpret_cast(reinterpret_cast(tfX.get()) + tfX->sizeInBytes); + auto yFromEnd = reinterpret_cast(reinterpret_cast(tfY.get()) + tfY->sizeInBytes); + auto zFromEnd = reinterpret_cast(reinterpret_cast(tfZ.get()) + tfZ->sizeInBytes); - // Count times slices get written (and clear out any leftover accumulation slices from last miplevel) - for( FilterFrom* zFrom = tfZ->from; zFrom < zFromEnd; ) - { - for ( size_t j = 0; j < zFrom->count; ++j ) + // Count times slices get written (and clear out any leftover accumulation slices from last miplevel) + for (FilterFrom* zFrom = tfZ->from; zFrom < zFromEnd; ) { - size_t w = zFrom->to[ j ].u; - assert( w < ndepth ); - TriangleRow* sliceAcc = &sliceActive[ w ]; - - ++sliceAcc->remaining; - - if ( sliceAcc->scanline ) + for (size_t j = 0; j < zFrom->count; ++j) { - memset( sliceAcc->scanline.get(), 0, sizeof(XMVECTOR) * nwidth * nheight ); + size_t w = zFrom->to[j].u; + assert(w < ndepth); + TriangleRow* sliceAcc = &sliceActive[w]; + + ++sliceAcc->remaining; + + if (sliceAcc->scanline) + { + memset(sliceAcc->scanline.get(), 0, sizeof(XMVECTOR) * nwidth * nheight); + } } + + zFrom = reinterpret_cast(reinterpret_cast(zFrom) + zFrom->sizeInBytes); } - zFrom = reinterpret_cast( reinterpret_cast( zFrom ) + zFrom->sizeInBytes ); - } - - // Filter image - size_t z = 0; - for( FilterFrom* zFrom = tfZ->from; zFrom < zFromEnd; ++z ) - { - // Create accumulation slices as needed - for ( size_t j = 0; j < zFrom->count; ++j ) + // Filter image + size_t z = 0; + for (FilterFrom* zFrom = tfZ->from; zFrom < zFromEnd; ++z) { - size_t w = zFrom->to[ j ].u; - assert( w < ndepth ); - TriangleRow* sliceAcc = &sliceActive[ w ]; - - if ( !sliceAcc->scanline ) + // Create accumulation slices as needed + for (size_t j = 0; j < zFrom->count; ++j) { - if ( sliceFree ) + size_t w = zFrom->to[j].u; + assert(w < ndepth); + TriangleRow* sliceAcc = &sliceActive[w]; + + if (!sliceAcc->scanline) { - // Steal and reuse scanline from 'free slice' list - // (it will always be at least as large as nwidth*nheight due to loop decending order) - assert( sliceFree->scanline != 0 ); - sliceAcc->scanline.reset( sliceFree->scanline.release() ); - sliceFree = sliceFree->next; - } - else - { - size_t bytes = sizeof(XMVECTOR) * nwidth * nheight; - sliceAcc->scanline.reset( reinterpret_cast( _aligned_malloc( bytes, 16 ) ) ); - if ( !sliceAcc->scanline ) - return E_OUTOFMEMORY; - } - - memset( sliceAcc->scanline.get(), 0, sizeof(XMVECTOR) * nwidth * nheight ); - } - } - - assert( z < depth ); - const Image* src = mipChain.GetImage( level-1, 0, z ); - if ( !src ) - return E_POINTER; - - const uint8_t* pSrc = src->pixels; - size_t rowPitch = src->rowPitch; - const uint8_t* pEndSrc = pSrc + rowPitch * height; - - for( FilterFrom* yFrom = tfY->from; yFrom < yFromEnd; ) - { - // Load source scanline - if ( (pSrc + rowPitch) > pEndSrc ) - return E_FAIL; - - if ( !_LoadScanlineLinear( row, width, pSrc, rowPitch, src->format, filter ) ) - return E_FAIL; - - pSrc += rowPitch; - - // Process row - size_t x = 0; - for( FilterFrom* xFrom = tfX->from; xFrom < xFromEnd; ++x ) - { - for ( size_t j = 0; j < zFrom->count; ++j ) - { - size_t w = zFrom->to[ j ].u; - assert( w < ndepth ); - float zweight = zFrom->to[ j ].weight; - - XMVECTOR* accSlice = sliceActive[ w ].scanline.get(); - if ( !accSlice ) - return E_POINTER; - - for ( size_t k = 0; k < yFrom->count; ++k ) + if (sliceFree) { - size_t v = yFrom->to[ k ].u; - assert( v < nheight ); - float yweight = yFrom->to[ k ].weight; + // Steal and reuse scanline from 'free slice' list + // (it will always be at least as large as nwidth*nheight due to loop decending order) + assert(sliceFree->scanline != 0); + sliceAcc->scanline.reset(sliceFree->scanline.release()); + sliceFree = sliceFree->next; + } + else + { + size_t bytes = sizeof(XMVECTOR) * nwidth * nheight; + sliceAcc->scanline.reset(reinterpret_cast(_aligned_malloc(bytes, 16))); + if (!sliceAcc->scanline) + return E_OUTOFMEMORY; + } - XMVECTOR * accPtr = accSlice + v * nwidth; + memset(sliceAcc->scanline.get(), 0, sizeof(XMVECTOR) * nwidth * nheight); + } + } - for ( size_t l = 0; l < xFrom->count; ++l ) + assert(z < depth); + const Image* src = mipChain.GetImage(level - 1, 0, z); + if (!src) + return E_POINTER; + + const uint8_t* pSrc = src->pixels; + size_t rowPitch = src->rowPitch; + const uint8_t* pEndSrc = pSrc + rowPitch * height; + + for (FilterFrom* yFrom = tfY->from; yFrom < yFromEnd; ) + { + // Load source scanline + if ((pSrc + rowPitch) > pEndSrc) + return E_FAIL; + + if (!_LoadScanlineLinear(row, width, pSrc, rowPitch, src->format, filter)) + return E_FAIL; + + pSrc += rowPitch; + + // Process row + size_t x = 0; + for (FilterFrom* xFrom = tfX->from; xFrom < xFromEnd; ++x) + { + for (size_t j = 0; j < zFrom->count; ++j) + { + size_t w = zFrom->to[j].u; + assert(w < ndepth); + float zweight = zFrom->to[j].weight; + + XMVECTOR* accSlice = sliceActive[w].scanline.get(); + if (!accSlice) + return E_POINTER; + + for (size_t k = 0; k < yFrom->count; ++k) { - size_t u = xFrom->to[ l ].u; - assert( u < nwidth ); + size_t v = yFrom->to[k].u; + assert(v < nheight); + float yweight = yFrom->to[k].weight; - XMVECTOR weight = XMVectorReplicate( zweight * yweight * xFrom->to[ l ].weight ); + XMVECTOR * accPtr = accSlice + v * nwidth; - assert( x < width ); - accPtr[ u ] = XMVectorMultiplyAdd( row[ x ], weight, accPtr[ u ] ); + for (size_t l = 0; l < xFrom->count; ++l) + { + size_t u = xFrom->to[l].u; + assert(u < nwidth); + + XMVECTOR weight = XMVectorReplicate(zweight * yweight * xFrom->to[l].weight); + + assert(x < width); + accPtr[u] = XMVectorMultiplyAdd(row[x], weight, accPtr[u]); + } } } + + xFrom = reinterpret_cast(reinterpret_cast(xFrom) + xFrom->sizeInBytes); } - xFrom = reinterpret_cast( reinterpret_cast( xFrom ) + xFrom->sizeInBytes ); + yFrom = reinterpret_cast(reinterpret_cast(yFrom) + yFrom->sizeInBytes); } - yFrom = reinterpret_cast( reinterpret_cast( yFrom ) + yFrom->sizeInBytes ); - } - - // Write completed accumulation slices - for ( size_t j = 0; j < zFrom->count; ++j ) - { - size_t w = zFrom->to[ j ].u; - assert( w < ndepth ); - TriangleRow* sliceAcc = &sliceActive[ w ]; - - assert( sliceAcc->remaining > 0 ); - --sliceAcc->remaining; - - if ( !sliceAcc->remaining ) + // Write completed accumulation slices + for (size_t j = 0; j < zFrom->count; ++j) { - const Image* dest = mipChain.GetImage( level, 0, w ); - XMVECTOR* pAccSrc = sliceAcc->scanline.get(); - if ( !dest || !pAccSrc ) - return E_POINTER; + size_t w = zFrom->to[j].u; + assert(w < ndepth); + TriangleRow* sliceAcc = &sliceActive[w]; - uint8_t* pDest = dest->pixels; + assert(sliceAcc->remaining > 0); + --sliceAcc->remaining; - for( size_t h = 0; h < nheight; ++h ) + if (!sliceAcc->remaining) { - switch( dest->format ) + const Image* dest = mipChain.GetImage(level, 0, w); + XMVECTOR* pAccSrc = sliceAcc->scanline.get(); + if (!dest || !pAccSrc) + return E_POINTER; + + uint8_t* pDest = dest->pixels; + + for (size_t h = 0; h < nheight; ++h) { - case DXGI_FORMAT_R10G10B10A2_UNORM: - case DXGI_FORMAT_R10G10B10A2_UINT: + switch (dest->format) + { + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: { // Need to slightly bias results for floating-point error accumulation which can // be visible with harshly quantized values static const XMVECTORF32 Bias = { 0.f, 0.f, 0.f, 0.1f }; - + XMVECTOR* ptr = pAccSrc; - for( size_t i=0; i < dest->width; ++i, ++ptr ) + for (size_t i = 0; i < dest->width; ++i, ++ptr) { - *ptr = XMVectorAdd( *ptr, Bias ); + *ptr = XMVectorAdd(*ptr, Bias); } } break; + } + + // This performs any required clamping + if (!_StoreScanlineLinear(pDest, dest->rowPitch, dest->format, pAccSrc, dest->width, filter)) + return E_FAIL; + + pDest += dest->rowPitch; + pAccSrc += nwidth; } - // This performs any required clamping - if ( !_StoreScanlineLinear( pDest, dest->rowPitch, dest->format, pAccSrc, dest->width, filter ) ) - return E_FAIL; - - pDest += dest->rowPitch; - pAccSrc += nwidth; + // Put slice on freelist to reuse it's allocated scanline + sliceAcc->next = sliceFree; + sliceFree = sliceAcc; } - - // Put slice on freelist to reuse it's allocated scanline - sliceAcc->next = sliceFree; - sliceFree = sliceAcc; } + + zFrom = reinterpret_cast(reinterpret_cast(zFrom) + zFrom->sizeInBytes); } - zFrom = reinterpret_cast( reinterpret_cast( zFrom ) + zFrom->sizeInBytes ); + if (height > 1) + height >>= 1; + + if (width > 1) + width >>= 1; + + if (depth > 1) + depth >>= 1; } - if ( height > 1 ) - height >>= 1; - - if ( width > 1 ) - width >>= 1; - - if ( depth > 1 ) - depth >>= 1; + return S_OK; } - - return S_OK; } @@ -2508,87 +2525,92 @@ static HRESULT _Generate3DMipsTriangleFilter( _In_ size_t depth, _In_ size_t lev // Generate mipmap chain //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT GenerateMipMaps( const Image& baseImage, DWORD filter, size_t levels, ScratchImage& mipChain, bool allow1D ) +HRESULT DirectX::GenerateMipMaps( + const Image& baseImage, + DWORD filter, + size_t levels, + ScratchImage& mipChain, + bool allow1D) { - if ( !IsValid( baseImage.format ) ) + if (!IsValid(baseImage.format)) return E_INVALIDARG; - if ( !baseImage.pixels ) + if (!baseImage.pixels) return E_POINTER; - if ( !_CalculateMipLevels(baseImage.width, baseImage.height, levels) ) + if (!_CalculateMipLevels(baseImage.width, baseImage.height, levels)) return E_INVALIDARG; - if ( levels <= 1 ) + if (levels <= 1) return E_INVALIDARG; - if ( IsCompressed(baseImage.format) || IsTypeless(baseImage.format) || IsPlanar(baseImage.format) || IsPalettized(baseImage.format) ) + if (IsCompressed(baseImage.format) || IsTypeless(baseImage.format) || IsPlanar(baseImage.format) || IsPalettized(baseImage.format)) { - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } HRESULT hr; - static_assert( TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK" ); + static_assert(TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK"); - if ( _UseWICFiltering( baseImage.format, filter ) ) + if (UseWICFiltering(baseImage.format, filter)) { //--- Use WIC filtering to generate mipmaps ----------------------------------- - switch(filter & TEX_FILTER_MASK) + switch (filter & TEX_FILTER_MASK) { - case 0: - case TEX_FILTER_POINT: - case TEX_FILTER_FANT: // Equivalent to Box filter - case TEX_FILTER_LINEAR: - case TEX_FILTER_CUBIC: - { - static_assert( TEX_FILTER_FANT == TEX_FILTER_BOX, "TEX_FILTER_ flag alias mismatch" ); + case 0: + case TEX_FILTER_POINT: + case TEX_FILTER_FANT: // Equivalent to Box filter + case TEX_FILTER_LINEAR: + case TEX_FILTER_CUBIC: + { + static_assert(TEX_FILTER_FANT == TEX_FILTER_BOX, "TEX_FILTER_ flag alias mismatch"); - WICPixelFormatGUID pfGUID; - if ( _DXGIToWIC( baseImage.format, pfGUID, true ) ) - { - // Case 1: Base image format is supported by Windows Imaging Component - 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; + WICPixelFormatGUID pfGUID; + if (_DXGIToWIC(baseImage.format, pfGUID, true)) + { + // Case 1: Base image format is supported by Windows Imaging Component + 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; - return _GenerateMipMapsUsingWIC( baseImage, filter, levels, pfGUID, mipChain, 0 ); - } - else - { - // 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; - hr = _ConvertToR32G32B32A32( baseImage, temp ); - if ( FAILED(hr) ) - return hr; + return GenerateMipMapsUsingWIC(baseImage, filter, levels, pfGUID, mipChain, 0); + } + else + { + // 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; + hr = _ConvertToR32G32B32A32(baseImage, temp); + if (FAILED(hr)) + return hr; - const Image *timg = temp.GetImage( 0, 0, 0 ); - if ( !timg ) - return E_POINTER; + const Image *timg = temp.GetImage(0, 0, 0); + if (!timg) + return E_POINTER; - ScratchImage tMipChain; - hr = (baseImage.height > 1 || !allow1D) - ? tMipChain.Initialize2D( DXGI_FORMAT_R32G32B32A32_FLOAT, baseImage.width, baseImage.height, 1, levels ) - : tMipChain.Initialize1D( DXGI_FORMAT_R32G32B32A32_FLOAT, baseImage.width, 1, levels ); - if ( FAILED(hr) ) - return hr; + ScratchImage tMipChain; + hr = (baseImage.height > 1 || !allow1D) + ? tMipChain.Initialize2D(DXGI_FORMAT_R32G32B32A32_FLOAT, baseImage.width, baseImage.height, 1, levels) + : tMipChain.Initialize1D(DXGI_FORMAT_R32G32B32A32_FLOAT, baseImage.width, 1, levels); + if (FAILED(hr)) + return hr; - hr = _GenerateMipMapsUsingWIC( *timg, filter, levels, GUID_WICPixelFormat128bppRGBAFloat, tMipChain, 0 ); - if ( FAILED(hr) ) - return hr; + hr = GenerateMipMapsUsingWIC(*timg, filter, levels, GUID_WICPixelFormat128bppRGBAFloat, tMipChain, 0); + if (FAILED(hr)) + return hr; - temp.Release(); + temp.Release(); - return _ConvertFromR32G32B32A32( tMipChain.GetImages(), tMipChain.GetImageCount(), tMipChain.GetMetadata(), baseImage.format, mipChain ); - } - } - break; + return _ConvertFromR32G32B32A32(tMipChain.GetImages(), tMipChain.GetImageCount(), tMipChain.GetMetadata(), baseImage.format, mipChain); + } + } + break; - default: - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + default: + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } } else @@ -2596,200 +2618,205 @@ HRESULT GenerateMipMaps( const Image& baseImage, DWORD filter, size_t levels, Sc //--- Use custom filters to generate mipmaps ---------------------------------- TexMetadata mdata = {}; mdata.width = baseImage.width; - if ( baseImage.height > 1 || !allow1D ) + if (baseImage.height > 1 || !allow1D) { - mdata.height = baseImage.height; + mdata.height = baseImage.height; mdata.dimension = TEX_DIMENSION_TEXTURE2D; } else { mdata.height = 1; - mdata.dimension= TEX_DIMENSION_TEXTURE1D; + mdata.dimension = TEX_DIMENSION_TEXTURE1D; } mdata.depth = mdata.arraySize = 1; mdata.mipLevels = levels; mdata.format = baseImage.format; - DWORD filter_select = ( filter & TEX_FILTER_MASK ); - if ( !filter_select ) + DWORD filter_select = (filter & TEX_FILTER_MASK); + if (!filter_select) { // Default filter choice - filter_select = ( ispow2(baseImage.width) && ispow2(baseImage.height) ) ? TEX_FILTER_BOX : TEX_FILTER_LINEAR; + filter_select = (ispow2(baseImage.width) && ispow2(baseImage.height)) ? TEX_FILTER_BOX : TEX_FILTER_LINEAR; } - switch( filter_select ) + switch (filter_select) { - case TEX_FILTER_BOX: - hr = _Setup2DMips( &baseImage, 1, mdata, mipChain ); - if ( FAILED(hr) ) - return hr; - - hr = _Generate2DMipsBoxFilter( levels, filter, mipChain, 0 ); - if ( FAILED(hr) ) - mipChain.Release(); + case TEX_FILTER_BOX: + hr = Setup2DMips(&baseImage, 1, mdata, mipChain); + if (FAILED(hr)) return hr; - case TEX_FILTER_POINT: - hr = _Setup2DMips( &baseImage, 1, mdata, mipChain ); - if ( FAILED(hr) ) - return hr; + hr = Generate2DMipsBoxFilter(levels, filter, mipChain, 0); + if (FAILED(hr)) + mipChain.Release(); + return hr; - hr = _Generate2DMipsPointFilter( levels, mipChain, 0 ); - if ( FAILED(hr) ) - mipChain.Release(); + case TEX_FILTER_POINT: + hr = Setup2DMips(&baseImage, 1, mdata, mipChain); + if (FAILED(hr)) return hr; - case TEX_FILTER_LINEAR: - hr = _Setup2DMips( &baseImage, 1, mdata, mipChain ); - if ( FAILED(hr) ) - return hr; + hr = Generate2DMipsPointFilter(levels, mipChain, 0); + if (FAILED(hr)) + mipChain.Release(); + return hr; - hr = _Generate2DMipsLinearFilter( levels, filter, mipChain, 0 ); - if ( FAILED(hr) ) - mipChain.Release(); + case TEX_FILTER_LINEAR: + hr = Setup2DMips(&baseImage, 1, mdata, mipChain); + if (FAILED(hr)) return hr; - case TEX_FILTER_CUBIC: - hr = _Setup2DMips( &baseImage, 1, mdata, mipChain ); - if ( FAILED(hr) ) - return hr; + hr = Generate2DMipsLinearFilter(levels, filter, mipChain, 0); + if (FAILED(hr)) + mipChain.Release(); + return hr; - hr = _Generate2DMipsCubicFilter( levels, filter, mipChain, 0 ); - if ( FAILED(hr) ) - mipChain.Release(); + case TEX_FILTER_CUBIC: + hr = Setup2DMips(&baseImage, 1, mdata, mipChain); + if (FAILED(hr)) return hr; - case TEX_FILTER_TRIANGLE: - hr = _Setup2DMips( &baseImage, 1, mdata, mipChain ); - if ( FAILED(hr) ) - return hr; + hr = Generate2DMipsCubicFilter(levels, filter, mipChain, 0); + if (FAILED(hr)) + mipChain.Release(); + return hr; - hr = _Generate2DMipsTriangleFilter( levels, filter, mipChain, 0 ); - if ( FAILED(hr) ) - mipChain.Release(); + case TEX_FILTER_TRIANGLE: + hr = Setup2DMips(&baseImage, 1, mdata, mipChain); + if (FAILED(hr)) return hr; - default: - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + hr = Generate2DMipsTriangleFilter(levels, filter, mipChain, 0); + if (FAILED(hr)) + mipChain.Release(); + return hr; + + default: + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } } } _Use_decl_annotations_ -HRESULT GenerateMipMaps( const Image* srcImages, size_t nimages, const TexMetadata& metadata, - DWORD filter, size_t levels, ScratchImage& mipChain ) +HRESULT DirectX::GenerateMipMaps( + const Image* srcImages, + size_t nimages, + const TexMetadata& metadata, + DWORD filter, + size_t levels, + ScratchImage& mipChain) { - if ( !srcImages || !nimages || !IsValid(metadata.format) ) + if (!srcImages || !nimages || !IsValid(metadata.format)) return E_INVALIDARG; - if ( metadata.IsVolumemap() - || IsCompressed(metadata.format) || IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format) ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if (metadata.IsVolumemap() + || 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) ) + if (!_CalculateMipLevels(metadata.width, metadata.height, levels)) return E_INVALIDARG; - if ( levels <= 1 ) + if (levels <= 1) return E_INVALIDARG; std::vector baseImages; - baseImages.reserve( metadata.arraySize ); - for( size_t item=0; item < metadata.arraySize; ++item ) + baseImages.reserve(metadata.arraySize); + for (size_t item = 0; item < metadata.arraySize; ++item) { - size_t index = metadata.ComputeIndex( 0, item, 0); - if ( index >= nimages ) + size_t index = metadata.ComputeIndex(0, item, 0); + if (index >= nimages) return E_FAIL; - const Image& src = srcImages[ index ]; - if ( !src.pixels ) + const Image& src = srcImages[index]; + if (!src.pixels) return E_POINTER; - if ( src.format != metadata.format || src.width != metadata.width || src.height != metadata.height ) + if (src.format != metadata.format || src.width != metadata.width || src.height != metadata.height) { // All base images must be the same format, width, and height return E_FAIL; } - baseImages.push_back( src ); + baseImages.push_back(src); } - assert( baseImages.size() == metadata.arraySize ); + assert(baseImages.size() == metadata.arraySize); HRESULT hr; - static_assert( TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK" ); + static_assert(TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK"); - if ( _UseWICFiltering( metadata.format, filter ) ) + if (UseWICFiltering(metadata.format, filter)) { //--- Use WIC filtering to generate mipmaps ----------------------------------- - switch(filter & TEX_FILTER_MASK) + switch (filter & TEX_FILTER_MASK) { case 0: case TEX_FILTER_POINT: case TEX_FILTER_FANT: // Equivalent to Box filter case TEX_FILTER_LINEAR: case TEX_FILTER_CUBIC: + { + static_assert(TEX_FILTER_FANT == TEX_FILTER_BOX, "TEX_FILTER_ flag alias mismatch"); + + WICPixelFormatGUID pfGUID; + if (_DXGIToWIC(metadata.format, pfGUID, true)) { - static_assert( TEX_FILTER_FANT == TEX_FILTER_BOX, "TEX_FILTER_ flag alias mismatch" ); + // Case 1: Base image format is supported by Windows Imaging Component + TexMetadata mdata2 = metadata; + mdata2.mipLevels = levels; + hr = mipChain.Initialize(mdata2); + if (FAILED(hr)) + return hr; - WICPixelFormatGUID pfGUID; - if ( _DXGIToWIC( metadata.format, pfGUID, true ) ) + for (size_t item = 0; item < metadata.arraySize; ++item) { - // Case 1: Base image format is supported by Windows Imaging Component - TexMetadata mdata2 = metadata; - mdata2.mipLevels = levels; - hr = mipChain.Initialize( mdata2 ); - if ( FAILED(hr) ) - return hr; - - for( size_t item = 0; item < metadata.arraySize; ++item ) + hr = GenerateMipMapsUsingWIC(baseImages[item], filter, levels, pfGUID, mipChain, item); + if (FAILED(hr)) { - hr = _GenerateMipMapsUsingWIC( baseImages[item], filter, levels, pfGUID, mipChain, item ); - if ( FAILED(hr) ) - { - mipChain.Release(); - return hr; - } - } - - return S_OK; - } - else - { - // Case 2: Base image format is not supported by WIC, so we have to convert, generate, and convert back - assert( metadata.format != DXGI_FORMAT_R32G32B32A32_FLOAT ); - - TexMetadata mdata2 = metadata; - mdata2.mipLevels = levels; - mdata2.format = DXGI_FORMAT_R32G32B32A32_FLOAT; - ScratchImage tMipChain; - hr = tMipChain.Initialize( mdata2 ); - if ( FAILED(hr) ) + mipChain.Release(); return hr; - - for( size_t item = 0; item < metadata.arraySize; ++item ) - { - ScratchImage temp; - hr = _ConvertToR32G32B32A32( baseImages[item], temp ); - if ( FAILED(hr) ) - return hr; - - const Image *timg = temp.GetImage( 0, 0, 0 ); - if ( !timg ) - return E_POINTER; - - hr = _GenerateMipMapsUsingWIC( *timg, filter, levels, GUID_WICPixelFormat128bppRGBAFloat, tMipChain, item ); - if ( FAILED(hr) ) - return hr; } - - return _ConvertFromR32G32B32A32( tMipChain.GetImages(), tMipChain.GetImageCount(), tMipChain.GetMetadata(), metadata.format, mipChain ); } + + return S_OK; } - break; + else + { + // Case 2: Base image format is not supported by WIC, so we have to convert, generate, and convert back + assert(metadata.format != DXGI_FORMAT_R32G32B32A32_FLOAT); + + TexMetadata mdata2 = metadata; + mdata2.mipLevels = levels; + mdata2.format = DXGI_FORMAT_R32G32B32A32_FLOAT; + ScratchImage tMipChain; + hr = tMipChain.Initialize(mdata2); + if (FAILED(hr)) + return hr; + + for (size_t item = 0; item < metadata.arraySize; ++item) + { + ScratchImage temp; + hr = _ConvertToR32G32B32A32(baseImages[item], temp); + if (FAILED(hr)) + return hr; + + const Image *timg = temp.GetImage(0, 0, 0); + if (!timg) + return E_POINTER; + + hr = GenerateMipMapsUsingWIC(*timg, filter, levels, GUID_WICPixelFormat128bppRGBAFloat, tMipChain, item); + if (FAILED(hr)) + return hr; + } + + return _ConvertFromR32G32B32A32(tMipChain.GetImages(), tMipChain.GetImageCount(), tMipChain.GetMetadata(), metadata.format, mipChain); + } + } + break; default: - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } } else @@ -2798,82 +2825,82 @@ HRESULT GenerateMipMaps( const Image* srcImages, size_t nimages, const TexMetada TexMetadata mdata2 = metadata; mdata2.mipLevels = levels; - DWORD filter_select = ( filter & TEX_FILTER_MASK ); - if ( !filter_select ) + DWORD filter_select = (filter & TEX_FILTER_MASK); + if (!filter_select) { // Default filter choice - filter_select = ( ispow2(metadata.width) && ispow2(metadata.height) ) ? TEX_FILTER_BOX : TEX_FILTER_LINEAR; + filter_select = (ispow2(metadata.width) && ispow2(metadata.height)) ? TEX_FILTER_BOX : TEX_FILTER_LINEAR; } - switch( filter_select ) + switch (filter_select) { - case TEX_FILTER_BOX: - hr = _Setup2DMips( &baseImages[0], metadata.arraySize, mdata2, mipChain ); - if ( FAILED(hr) ) - return hr; - - for( size_t item = 0; item < metadata.arraySize; ++item ) - { - hr = _Generate2DMipsBoxFilter( levels, filter, mipChain, item ); - if ( FAILED(hr) ) - mipChain.Release(); - } + case TEX_FILTER_BOX: + hr = Setup2DMips(&baseImages[0], metadata.arraySize, mdata2, mipChain); + if (FAILED(hr)) return hr; - case TEX_FILTER_POINT: - hr = _Setup2DMips( &baseImages[0], metadata.arraySize, mdata2, mipChain ); - if ( FAILED(hr) ) - return hr; + for (size_t item = 0; item < metadata.arraySize; ++item) + { + hr = Generate2DMipsBoxFilter(levels, filter, mipChain, item); + if (FAILED(hr)) + mipChain.Release(); + } + return hr; - for( size_t item = 0; item < metadata.arraySize; ++item ) - { - hr = _Generate2DMipsPointFilter( levels, mipChain, item ); - if ( FAILED(hr) ) - mipChain.Release(); - } + case TEX_FILTER_POINT: + hr = Setup2DMips(&baseImages[0], metadata.arraySize, mdata2, mipChain); + if (FAILED(hr)) return hr; - case TEX_FILTER_LINEAR: - hr = _Setup2DMips( &baseImages[0], metadata.arraySize, mdata2, mipChain ); - if ( FAILED(hr) ) - return hr; + for (size_t item = 0; item < metadata.arraySize; ++item) + { + hr = Generate2DMipsPointFilter(levels, mipChain, item); + if (FAILED(hr)) + mipChain.Release(); + } + return hr; - for( size_t item = 0; item < metadata.arraySize; ++item ) - { - hr = _Generate2DMipsLinearFilter( levels, filter, mipChain, item ); - if ( FAILED(hr) ) - mipChain.Release(); - } + case TEX_FILTER_LINEAR: + hr = Setup2DMips(&baseImages[0], metadata.arraySize, mdata2, mipChain); + if (FAILED(hr)) return hr; - case TEX_FILTER_CUBIC: - hr = _Setup2DMips( &baseImages[0], metadata.arraySize, mdata2, mipChain ); - if ( FAILED(hr) ) - return hr; + for (size_t item = 0; item < metadata.arraySize; ++item) + { + hr = Generate2DMipsLinearFilter(levels, filter, mipChain, item); + if (FAILED(hr)) + mipChain.Release(); + } + return hr; - for( size_t item = 0; item < metadata.arraySize; ++item ) - { - hr = _Generate2DMipsCubicFilter( levels, filter, mipChain, item ); - if ( FAILED(hr) ) - mipChain.Release(); - } + case TEX_FILTER_CUBIC: + hr = Setup2DMips(&baseImages[0], metadata.arraySize, mdata2, mipChain); + if (FAILED(hr)) return hr; - case TEX_FILTER_TRIANGLE: - hr = _Setup2DMips( &baseImages[0], metadata.arraySize, mdata2, mipChain ); - if ( FAILED(hr) ) - return hr; + for (size_t item = 0; item < metadata.arraySize; ++item) + { + hr = Generate2DMipsCubicFilter(levels, filter, mipChain, item); + if (FAILED(hr)) + mipChain.Release(); + } + return hr; - for( size_t item = 0; item < metadata.arraySize; ++item ) - { - hr = _Generate2DMipsTriangleFilter( levels, filter, mipChain, item ); - if ( FAILED(hr) ) - mipChain.Release(); - } + case TEX_FILTER_TRIANGLE: + hr = Setup2DMips(&baseImages[0], metadata.arraySize, mdata2, mipChain); + if (FAILED(hr)) return hr; - default: - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + for (size_t item = 0; item < metadata.arraySize; ++item) + { + hr = Generate2DMipsTriangleFilter(levels, filter, mipChain, item); + if (FAILED(hr)) + mipChain.Release(); + } + return hr; + + default: + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } } } @@ -2883,216 +2910,224 @@ HRESULT GenerateMipMaps( const Image* srcImages, size_t nimages, const TexMetada // Generate mipmap chain for volume texture //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT GenerateMipMaps3D( const Image* baseImages, size_t depth, DWORD filter, size_t levels, ScratchImage& mipChain ) +HRESULT DirectX::GenerateMipMaps3D( + const Image* baseImages, + size_t depth, + DWORD filter, + size_t levels, + ScratchImage& mipChain) { - if ( !baseImages || !depth ) + if (!baseImages || !depth) return E_INVALIDARG; - if ( filter & TEX_FILTER_FORCE_WIC ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if (filter & TEX_FILTER_FORCE_WIC) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); DXGI_FORMAT format = baseImages[0].format; size_t width = baseImages[0].width; size_t height = baseImages[0].height; - if ( !_CalculateMipLevels3D(width, height, depth, levels) ) + if (!_CalculateMipLevels3D(width, height, depth, levels)) return E_INVALIDARG; - if ( levels <= 1 ) + if (levels <= 1) return E_INVALIDARG; - for( size_t slice=0; slice < depth; ++slice ) + for (size_t slice = 0; slice < depth; ++slice) { - if ( !baseImages[slice].pixels ) + if (!baseImages[slice].pixels) return E_POINTER; - if ( baseImages[slice].format != format || baseImages[slice].width != width || baseImages[slice].height != height ) + if (baseImages[slice].format != format || baseImages[slice].width != width || baseImages[slice].height != height) { // All base images must be the same format, width, and height return E_FAIL; } } - if ( IsCompressed(format) || IsTypeless(format) || IsPlanar(format) || IsPalettized(format) ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + 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" ); + static_assert(TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK"); HRESULT hr; - DWORD filter_select = ( filter & TEX_FILTER_MASK ); - if ( !filter_select ) + DWORD filter_select = (filter & TEX_FILTER_MASK); + if (!filter_select) { // Default filter choice - filter_select = ( ispow2(width) && ispow2(height) && ispow2(depth) ) ? TEX_FILTER_BOX : TEX_FILTER_TRIANGLE; + filter_select = (ispow2(width) && ispow2(height) && ispow2(depth)) ? TEX_FILTER_BOX : TEX_FILTER_TRIANGLE; } - switch( filter_select ) + switch (filter_select) { case TEX_FILTER_BOX: - hr = _Setup3DMips( baseImages, depth, levels, mipChain ); - if ( FAILED(hr) ) + hr = Setup3DMips(baseImages, depth, levels, mipChain); + if (FAILED(hr)) return hr; - hr = _Generate3DMipsBoxFilter( depth, levels, filter, mipChain ); - if ( FAILED(hr) ) + hr = Generate3DMipsBoxFilter(depth, levels, filter, mipChain); + if (FAILED(hr)) mipChain.Release(); return hr; case TEX_FILTER_POINT: - hr = _Setup3DMips( baseImages, depth, levels, mipChain ); - if ( FAILED(hr) ) + hr = Setup3DMips(baseImages, depth, levels, mipChain); + if (FAILED(hr)) return hr; - hr = _Generate3DMipsPointFilter( depth, levels, mipChain ); - if ( FAILED(hr) ) + hr = Generate3DMipsPointFilter(depth, levels, mipChain); + if (FAILED(hr)) mipChain.Release(); return hr; case TEX_FILTER_LINEAR: - hr = _Setup3DMips( baseImages, depth, levels, mipChain ); - if ( FAILED(hr) ) + hr = Setup3DMips(baseImages, depth, levels, mipChain); + if (FAILED(hr)) return hr; - hr = _Generate3DMipsLinearFilter( depth, levels, filter, mipChain ); - if ( FAILED(hr) ) + hr = Generate3DMipsLinearFilter(depth, levels, filter, mipChain); + if (FAILED(hr)) mipChain.Release(); return hr; case TEX_FILTER_CUBIC: - hr = _Setup3DMips( baseImages, depth, levels, mipChain ); - if ( FAILED(hr) ) + hr = Setup3DMips(baseImages, depth, levels, mipChain); + if (FAILED(hr)) return hr; - hr = _Generate3DMipsCubicFilter( depth, levels, filter, mipChain ); - if ( FAILED(hr) ) + hr = Generate3DMipsCubicFilter(depth, levels, filter, mipChain); + if (FAILED(hr)) mipChain.Release(); return hr; case TEX_FILTER_TRIANGLE: - hr = _Setup3DMips( baseImages, depth, levels, mipChain ); - if ( FAILED(hr) ) + hr = Setup3DMips(baseImages, depth, levels, mipChain); + if (FAILED(hr)) return hr; - hr = _Generate3DMipsTriangleFilter( depth, levels, filter, mipChain ); - if ( FAILED(hr) ) + hr = Generate3DMipsTriangleFilter(depth, levels, filter, mipChain); + if (FAILED(hr)) mipChain.Release(); return hr; default: - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } } _Use_decl_annotations_ -HRESULT GenerateMipMaps3D( const Image* srcImages, size_t nimages, const TexMetadata& metadata, - DWORD filter, size_t levels, ScratchImage& mipChain ) +HRESULT DirectX::GenerateMipMaps3D( + const Image* srcImages, + size_t nimages, + const TexMetadata& metadata, + DWORD filter, + size_t levels, + ScratchImage& mipChain) { - if ( !srcImages || !nimages || !IsValid(metadata.format) ) + if (!srcImages || !nimages || !IsValid(metadata.format)) return E_INVALIDARG; - if ( filter & TEX_FILTER_FORCE_WIC ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if (filter & TEX_FILTER_FORCE_WIC) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); - if ( !metadata.IsVolumemap() - || IsCompressed(metadata.format) || IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format) ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if (!metadata.IsVolumemap() + || 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) ) + if (!_CalculateMipLevels3D(metadata.width, metadata.height, metadata.depth, levels)) return E_INVALIDARG; - if ( levels <= 1 ) + if (levels <= 1) return E_INVALIDARG; std::vector baseImages; - baseImages.reserve( metadata.depth ); - for( size_t slice=0; slice < metadata.depth; ++slice ) + baseImages.reserve(metadata.depth); + for (size_t slice = 0; slice < metadata.depth; ++slice) { - size_t index = metadata.ComputeIndex( 0, 0, slice ); - if ( index >= nimages ) + size_t index = metadata.ComputeIndex(0, 0, slice); + if (index >= nimages) return E_FAIL; - const Image& src = srcImages[ index ]; - if ( !src.pixels ) + const Image& src = srcImages[index]; + if (!src.pixels) return E_POINTER; - if ( src.format != metadata.format || src.width != metadata.width || src.height != metadata.height ) + if (src.format != metadata.format || src.width != metadata.width || src.height != metadata.height) { // All base images must be the same format, width, and height return E_FAIL; } - baseImages.push_back( src ); + baseImages.push_back(src); } - assert( baseImages.size() == metadata.depth ); + assert(baseImages.size() == metadata.depth); HRESULT hr; - static_assert( TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK" ); + static_assert(TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK"); - DWORD filter_select = ( filter & TEX_FILTER_MASK ); - if ( !filter_select ) + DWORD filter_select = (filter & TEX_FILTER_MASK); + if (!filter_select) { // Default filter choice - filter_select = ( ispow2(metadata.width) && ispow2(metadata.height) && ispow2(metadata.depth) ) ? TEX_FILTER_BOX : TEX_FILTER_TRIANGLE; + filter_select = (ispow2(metadata.width) && ispow2(metadata.height) && ispow2(metadata.depth)) ? TEX_FILTER_BOX : TEX_FILTER_TRIANGLE; } - switch( filter_select ) + switch (filter_select) { case TEX_FILTER_BOX: - hr = _Setup3DMips( &baseImages[0], metadata.depth, levels, mipChain ); - if ( FAILED(hr) ) + hr = Setup3DMips(&baseImages[0], metadata.depth, levels, mipChain); + if (FAILED(hr)) return hr; - hr = _Generate3DMipsBoxFilter( metadata.depth, levels, filter, mipChain ); - if ( FAILED(hr) ) + hr = Generate3DMipsBoxFilter(metadata.depth, levels, filter, mipChain); + if (FAILED(hr)) mipChain.Release(); return hr; case TEX_FILTER_POINT: - hr = _Setup3DMips( &baseImages[0], metadata.depth, levels, mipChain ); - if ( FAILED(hr) ) + hr = Setup3DMips(&baseImages[0], metadata.depth, levels, mipChain); + if (FAILED(hr)) return hr; - hr = _Generate3DMipsPointFilter( metadata.depth, levels, mipChain ); - if ( FAILED(hr) ) + hr = Generate3DMipsPointFilter(metadata.depth, levels, mipChain); + if (FAILED(hr)) mipChain.Release(); return hr; case TEX_FILTER_LINEAR: - hr = _Setup3DMips( &baseImages[0], metadata.depth, levels, mipChain ); - if ( FAILED(hr) ) + hr = Setup3DMips(&baseImages[0], metadata.depth, levels, mipChain); + if (FAILED(hr)) return hr; - hr = _Generate3DMipsLinearFilter( metadata.depth, levels, filter, mipChain ); - if ( FAILED(hr) ) + hr = Generate3DMipsLinearFilter(metadata.depth, levels, filter, mipChain); + if (FAILED(hr)) mipChain.Release(); return hr; case TEX_FILTER_CUBIC: - hr = _Setup3DMips( &baseImages[0], metadata.depth, levels, mipChain ); - if ( FAILED(hr) ) + hr = Setup3DMips(&baseImages[0], metadata.depth, levels, mipChain); + if (FAILED(hr)) return hr; - hr = _Generate3DMipsCubicFilter( metadata.depth, levels, filter, mipChain ); - if ( FAILED(hr) ) + hr = Generate3DMipsCubicFilter(metadata.depth, levels, filter, mipChain); + if (FAILED(hr)) mipChain.Release(); return hr; case TEX_FILTER_TRIANGLE: - hr = _Setup3DMips( &baseImages[0], metadata.depth, levels, mipChain ); - if ( FAILED(hr) ) + hr = Setup3DMips(&baseImages[0], metadata.depth, levels, mipChain); + if (FAILED(hr)) return hr; - hr = _Generate3DMipsTriangleFilter( metadata.depth, levels, filter, mipChain ); - if ( FAILED(hr) ) + hr = Generate3DMipsTriangleFilter(metadata.depth, levels, filter, mipChain); + if (FAILED(hr)) mipChain.Release(); return hr; default: - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } } - -}; // namespace diff --git a/DirectXTex/DirectXTexMisc.cpp b/DirectXTex/DirectXTexMisc.cpp index 799316f..61a37ad 100644 --- a/DirectXTex/DirectXTexMisc.cpp +++ b/DirectXTex/DirectXTexMisc.cpp @@ -15,152 +15,158 @@ #include "directxtexp.h" -namespace DirectX +using namespace DirectX; + +namespace { -static const XMVECTORF32 g_Gamma22 = { 2.2f, 2.2f, 2.2f, 1.f }; + const XMVECTORF32 g_Gamma22 = { 2.2f, 2.2f, 2.2f, 1.f }; -//------------------------------------------------------------------------------------- -static HRESULT _ComputeMSE( _In_ const Image& image1, _In_ const Image& image2, - _Out_ float& mse, _Out_writes_opt_(4) float* mseV, - _In_ DWORD flags ) -{ - if ( !image1.pixels || !image2.pixels ) - return E_POINTER; - - assert( image1.width == image2.width && image1.height == image2.height ); - assert( !IsCompressed( image1.format ) && !IsCompressed( image2.format ) ); - - const size_t width = image1.width; - - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( (sizeof(XMVECTOR)*width)*2, 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - // Flags implied from image formats - switch( image1.format ) + //------------------------------------------------------------------------------------- + HRESULT ComputeMSE_( + const Image& image1, + const Image& image2, + float& mse, + _Out_writes_opt_(4) float* mseV, + DWORD flags) { - case DXGI_FORMAT_B8G8R8X8_UNORM: - flags |= CMSE_IGNORE_ALPHA; - break; + if (!image1.pixels || !image2.pixels) + return E_POINTER; - case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: - flags |= CMSE_IMAGE1_SRGB | CMSE_IGNORE_ALPHA; - break; + assert(image1.width == image2.width && image1.height == image2.height); + assert(!IsCompressed(image1.format) && !IsCompressed(image2.format)); - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - case DXGI_FORMAT_BC1_UNORM_SRGB: - case DXGI_FORMAT_BC2_UNORM_SRGB: - case DXGI_FORMAT_BC3_UNORM_SRGB: - case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: - case DXGI_FORMAT_BC7_UNORM_SRGB: - flags |= CMSE_IMAGE1_SRGB; - break; - } + const size_t width = image1.width; - switch( image2.format ) - { - case DXGI_FORMAT_B8G8R8X8_UNORM: - flags |= CMSE_IGNORE_ALPHA; - break; + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc((sizeof(XMVECTOR)*width) * 2, 16))); + if (!scanline) + return E_OUTOFMEMORY; - case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: - flags |= CMSE_IMAGE2_SRGB | CMSE_IGNORE_ALPHA; - break; - - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - case DXGI_FORMAT_BC1_UNORM_SRGB: - case DXGI_FORMAT_BC2_UNORM_SRGB: - case DXGI_FORMAT_BC3_UNORM_SRGB: - case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: - case DXGI_FORMAT_BC7_UNORM_SRGB: - flags |= CMSE_IMAGE2_SRGB; - break; - } - - const uint8_t *pSrc1 = image1.pixels; - const size_t rowPitch1 = image1.rowPitch; - - const uint8_t *pSrc2 = image2.pixels; - const size_t rowPitch2 = image2.rowPitch; - - XMVECTOR acc = g_XMZero; - static XMVECTORF32 two = { 2.0f, 2.0f, 2.0f, 2.0f }; - - for( size_t h = 0; h < image1.height; ++h ) - { - XMVECTOR* ptr1 = scanline.get(); - if ( !_LoadScanline( ptr1, width, pSrc1, rowPitch1, image1.format ) ) - return E_FAIL; - - XMVECTOR* ptr2 = scanline.get() + width; - if ( !_LoadScanline( ptr2, width, pSrc2, rowPitch2, image2.format ) ) - return E_FAIL; - - for( size_t i = 0; i < width; ++i ) + // Flags implied from image formats + switch (image1.format) { - XMVECTOR v1 = *(ptr1++); - if ( flags & CMSE_IMAGE1_SRGB ) - { - v1 = XMVectorPow( v1, g_Gamma22 ); - } - if ( flags & CMSE_IMAGE1_X2_BIAS ) - { - v1 = XMVectorMultiplyAdd( v1, two, g_XMNegativeOne ); - } + case DXGI_FORMAT_B8G8R8X8_UNORM: + flags |= CMSE_IGNORE_ALPHA; + break; - XMVECTOR v2 = *(ptr2++); - if ( flags & CMSE_IMAGE2_SRGB ) - { - v2 = XMVectorPow( v2, g_Gamma22 ); - } - if ( flags & CMSE_IMAGE2_X2_BIAS ) - { - v1 = XMVectorMultiplyAdd( v2, two, g_XMNegativeOne ); - } + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + flags |= CMSE_IMAGE1_SRGB | CMSE_IGNORE_ALPHA; + break; - // sum[ (I1 - I2)^2 ] - XMVECTOR v = XMVectorSubtract( v1, v2 ); - if ( flags & CMSE_IGNORE_RED ) - { - v = XMVectorSelect( v, g_XMZero, g_XMMaskX ); - } - if ( flags & CMSE_IGNORE_GREEN ) - { - v = XMVectorSelect( v, g_XMZero, g_XMMaskY ); - } - if ( flags & CMSE_IGNORE_BLUE ) - { - v = XMVectorSelect( v, g_XMZero, g_XMMaskZ ); - } - if ( flags & CMSE_IGNORE_ALPHA ) - { - v = XMVectorSelect( v, g_XMZero, g_XMMaskW ); - } - - acc = XMVectorMultiplyAdd( v, v, acc ); + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_BC7_UNORM_SRGB: + flags |= CMSE_IMAGE1_SRGB; + break; } - pSrc1 += rowPitch1; - pSrc2 += rowPitch2; - } + switch (image2.format) + { + case DXGI_FORMAT_B8G8R8X8_UNORM: + flags |= CMSE_IGNORE_ALPHA; + break; - // MSE = sum[ (I1 - I2)^2 ] / w*h - XMVECTOR d = XMVectorReplicate( float(image1.width * image1.height) ); - XMVECTOR v = XMVectorDivide( acc, d ); - if ( mseV ) - { - XMStoreFloat4( reinterpret_cast( mseV ), v ); - mse = mseV[0] + mseV[1] + mseV[2] + mseV[3]; - } - else - { - XMFLOAT4 _mseV; - XMStoreFloat4( &_mseV, v ); - mse = _mseV.x + _mseV.y + _mseV.z + _mseV.w; - } + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + flags |= CMSE_IMAGE2_SRGB | CMSE_IGNORE_ALPHA; + break; - return S_OK; -} + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_BC7_UNORM_SRGB: + flags |= CMSE_IMAGE2_SRGB; + break; + } + + const uint8_t *pSrc1 = image1.pixels; + const size_t rowPitch1 = image1.rowPitch; + + const uint8_t *pSrc2 = image2.pixels; + const size_t rowPitch2 = image2.rowPitch; + + XMVECTOR acc = g_XMZero; + static XMVECTORF32 two = { 2.0f, 2.0f, 2.0f, 2.0f }; + + for (size_t h = 0; h < image1.height; ++h) + { + XMVECTOR* ptr1 = scanline.get(); + if (!_LoadScanline(ptr1, width, pSrc1, rowPitch1, image1.format)) + return E_FAIL; + + XMVECTOR* ptr2 = scanline.get() + width; + if (!_LoadScanline(ptr2, width, pSrc2, rowPitch2, image2.format)) + return E_FAIL; + + for (size_t i = 0; i < width; ++i) + { + XMVECTOR v1 = *(ptr1++); + if (flags & CMSE_IMAGE1_SRGB) + { + v1 = XMVectorPow(v1, g_Gamma22); + } + if (flags & CMSE_IMAGE1_X2_BIAS) + { + v1 = XMVectorMultiplyAdd(v1, two, g_XMNegativeOne); + } + + XMVECTOR v2 = *(ptr2++); + if (flags & CMSE_IMAGE2_SRGB) + { + v2 = XMVectorPow(v2, g_Gamma22); + } + if (flags & CMSE_IMAGE2_X2_BIAS) + { + v1 = XMVectorMultiplyAdd(v2, two, g_XMNegativeOne); + } + + // sum[ (I1 - I2)^2 ] + XMVECTOR v = XMVectorSubtract(v1, v2); + if (flags & CMSE_IGNORE_RED) + { + v = XMVectorSelect(v, g_XMZero, g_XMMaskX); + } + if (flags & CMSE_IGNORE_GREEN) + { + v = XMVectorSelect(v, g_XMZero, g_XMMaskY); + } + if (flags & CMSE_IGNORE_BLUE) + { + v = XMVectorSelect(v, g_XMZero, g_XMMaskZ); + } + if (flags & CMSE_IGNORE_ALPHA) + { + v = XMVectorSelect(v, g_XMZero, g_XMMaskW); + } + + acc = XMVectorMultiplyAdd(v, v, acc); + } + + pSrc1 += rowPitch1; + pSrc2 += rowPitch2; + } + + // MSE = sum[ (I1 - I2)^2 ] / w*h + XMVECTOR d = XMVectorReplicate(float(image1.width * image1.height)); + XMVECTOR v = XMVectorDivide(acc, d); + if (mseV) + { + XMStoreFloat4(reinterpret_cast(mseV), v); + mse = mseV[0] + mseV[1] + mseV[2] + mseV[3]; + } + else + { + XMFLOAT4 _mseV; + XMStoreFloat4(&_mseV, v); + mse = _mseV.x + _mseV.y + _mseV.z + _mseV.w; + } + + return S_OK; + } +}; //===================================================================================== @@ -171,57 +177,63 @@ static HRESULT _ComputeMSE( _In_ const Image& image1, _In_ const Image& image2, // Copies a rectangle from one image into another //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT CopyRectangle( const Image& srcImage, const Rect& srcRect, const Image& dstImage, DWORD filter, size_t xOffset, size_t yOffset ) +HRESULT DirectX::CopyRectangle( + const Image& srcImage, + const Rect& srcRect, + const Image& dstImage, + DWORD filter, + size_t xOffset, + size_t yOffset) { - if ( !srcImage.pixels || !dstImage.pixels ) + if (!srcImage.pixels || !dstImage.pixels) return E_POINTER; - 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 ); + 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 - if ( !srcRect.w || !srcRect.h || ( (srcRect.x + srcRect.w) > srcImage.width ) || ( (srcRect.y + srcRect.h) > srcImage.height ) ) + if (!srcRect.w || !srcRect.h || ((srcRect.x + srcRect.w) > srcImage.width) || ((srcRect.y + srcRect.h) > srcImage.height)) { return E_INVALIDARG; } - if ( ( (xOffset + srcRect.w) > dstImage.width ) || ( (yOffset + srcRect.h) > dstImage.height ) ) + if (((xOffset + srcRect.w) > dstImage.width) || ((yOffset + srcRect.h) > dstImage.height)) { return E_INVALIDARG; } // Compute source bytes-per-pixel - size_t sbpp = BitsPerPixel( srcImage.format ); - if ( !sbpp ) + size_t sbpp = BitsPerPixel(srcImage.format); + if (!sbpp) return E_FAIL; - if ( sbpp < 8 ) + if (sbpp < 8) { // We don't support monochrome (DXGI_FORMAT_R1_UNORM) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } const uint8_t* pEndSrc = srcImage.pixels + srcImage.rowPitch*srcImage.height; const uint8_t* pEndDest = dstImage.pixels + dstImage.rowPitch*dstImage.height; // Round to bytes - sbpp = ( sbpp + 7 ) / 8; + sbpp = (sbpp + 7) / 8; const uint8_t* pSrc = srcImage.pixels + (srcRect.y * srcImage.rowPitch) + (srcRect.x * sbpp); - if ( srcImage.format == dstImage.format ) + if (srcImage.format == dstImage.format) { // Direct copy case (avoid intermediate conversions) uint8_t* pDest = dstImage.pixels + (yOffset * dstImage.rowPitch) + (xOffset * sbpp); const size_t copyW = srcRect.w * sbpp; - for( size_t h=0; h < srcRect.h; ++h ) + for (size_t h = 0; h < srcRect.h; ++h) { - if ( ( (pSrc+copyW) > pEndSrc ) || (pDest > pEndDest) ) + if (((pSrc + copyW) > pEndSrc) || (pDest > pEndDest)) return E_FAIL; - memcpy_s( pDest, pEndDest - pDest, pSrc, copyW ); + memcpy_s(pDest, pEndDest - pDest, pSrc, copyW); pSrc += srcImage.rowPitch; pDest += dstImage.rowPitch; @@ -231,39 +243,39 @@ HRESULT CopyRectangle( const Image& srcImage, const Rect& srcRect, const Image& } // Compute destination bytes-per-pixel (not the same format as source) - size_t dbpp = BitsPerPixel( dstImage.format ); - if ( !dbpp ) + size_t dbpp = BitsPerPixel(dstImage.format); + if (!dbpp) return E_FAIL; - if ( dbpp < 8 ) + if (dbpp < 8) { // We don't support monochrome (DXGI_FORMAT_R1_UNORM) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } // Round to bytes - dbpp = ( dbpp + 7 ) / 8; + dbpp = (dbpp + 7) / 8; uint8_t* pDest = dstImage.pixels + (yOffset * dstImage.rowPitch) + (xOffset * dbpp); - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( (sizeof(XMVECTOR)*srcRect.w), 16 ) ) ); - if ( !scanline ) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc((sizeof(XMVECTOR)*srcRect.w), 16))); + if (!scanline) return E_OUTOFMEMORY; const size_t copyS = srcRect.w * sbpp; const size_t copyD = srcRect.w * dbpp; - for( size_t h=0; h < srcRect.h; ++h ) + for (size_t h = 0; h < srcRect.h; ++h) { - if ( ( (pSrc+copyS) > pEndSrc) || ((pDest+copyD) > pEndDest) ) + if (((pSrc + copyS) > pEndSrc) || ((pDest + copyD) > pEndDest)) return E_FAIL; - if ( !_LoadScanline( scanline.get(), srcRect.w, pSrc, copyS, srcImage.format ) ) + if (!_LoadScanline(scanline.get(), srcRect.w, pSrc, copyS, srcImage.format)) return E_FAIL; - _ConvertScanline( scanline.get(), srcRect.w, dstImage.format, srcImage.format, filter ); + _ConvertScanline(scanline.get(), srcRect.w, dstImage.format, srcImage.format, filter); - if ( !_StoreScanline( pDest, copyD, dstImage.format, scanline.get(), srcRect.w ) ) + if (!_StoreScanline(pDest, copyD, dstImage.format, scanline.get(), srcRect.w)) return E_FAIL; pSrc += srcImage.rowPitch; @@ -278,77 +290,80 @@ HRESULT CopyRectangle( const Image& srcImage, const Rect& srcRect, const Image& // Computes the Mean-Squared-Error (MSE) between two images //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT ComputeMSE( const Image& image1, const Image& image2, float& mse, float* mseV, DWORD flags ) +HRESULT DirectX::ComputeMSE( + const Image& image1, + const Image& image2, + float& mse, + float* mseV, + DWORD flags) { - if ( !image1.pixels || !image2.pixels ) + if (!image1.pixels || !image2.pixels) return E_POINTER; - if ( image1.width != image2.width || image1.height != image2.height ) + 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 (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(image1.format)) { - if ( IsCompressed(image2.format) ) + if (IsCompressed(image2.format)) { // Case 1: both images are compressed, expand to RGBA32F ScratchImage temp1; - HRESULT hr = Decompress( image1, DXGI_FORMAT_R32G32B32A32_FLOAT, temp1 ); - if ( FAILED(hr) ) + HRESULT hr = Decompress(image1, DXGI_FORMAT_R32G32B32A32_FLOAT, temp1); + if (FAILED(hr)) return hr; ScratchImage temp2; - hr = Decompress( image2, DXGI_FORMAT_R32G32B32A32_FLOAT, temp2 ); - if ( FAILED(hr) ) + hr = Decompress(image2, DXGI_FORMAT_R32G32B32A32_FLOAT, temp2); + if (FAILED(hr)) return hr; - const Image* img1 = temp1.GetImage(0,0,0); - const Image* img2 = temp2.GetImage(0,0,0); - if ( !img1 || !img2 ) + const Image* img1 = temp1.GetImage(0, 0, 0); + const Image* img2 = temp2.GetImage(0, 0, 0); + if (!img1 || !img2) return E_POINTER; - return _ComputeMSE( *img1, *img2, mse, mseV, flags ); + return ComputeMSE_(*img1, *img2, mse, mseV, flags); } else { // Case 2: image1 is compressed, expand to RGBA32F ScratchImage temp; - HRESULT hr = Decompress( image1, DXGI_FORMAT_R32G32B32A32_FLOAT, temp ); - if ( FAILED(hr) ) + HRESULT hr = Decompress(image1, DXGI_FORMAT_R32G32B32A32_FLOAT, temp); + if (FAILED(hr)) return hr; - const Image* img = temp.GetImage(0,0,0); - if ( !img ) + const Image* img = temp.GetImage(0, 0, 0); + if (!img) return E_POINTER; - return _ComputeMSE( *img, image2, mse, mseV, flags ); + return ComputeMSE_(*img, image2, mse, mseV, flags); } } else { - if ( IsCompressed(image2.format) ) + if (IsCompressed(image2.format)) { // Case 3: image2 is compressed, expand to RGBA32F ScratchImage temp; - HRESULT hr = Decompress( image2, DXGI_FORMAT_R32G32B32A32_FLOAT, temp ); - if ( FAILED(hr) ) + HRESULT hr = Decompress(image2, DXGI_FORMAT_R32G32B32A32_FLOAT, temp); + if (FAILED(hr)) return hr; - const Image* img = temp.GetImage(0,0,0); - if ( !img ) + const Image* img = temp.GetImage(0, 0, 0); + if (!img) return E_POINTER; - return _ComputeMSE( image1, *img, mse, mseV, flags ); + return ComputeMSE_(image1, *img, mse, mseV, flags); } else { // Case 4: neither image is compressed - return _ComputeMSE( image1, image2, mse, mseV, flags ); + return ComputeMSE_(image1, image2, mse, mseV, flags); } } } - -}; // namespace diff --git a/DirectXTex/DirectXTexNormalMaps.cpp b/DirectXTex/DirectXTexNormalMaps.cpp index 4343ad3..051676f 100644 --- a/DirectXTex/DirectXTexNormalMaps.cpp +++ b/DirectXTex/DirectXTexNormalMaps.cpp @@ -15,232 +15,238 @@ #include "directxtexp.h" -namespace DirectX +using namespace DirectX; + +namespace { #pragma prefast(suppress : 25000, "FXMVECTOR is 16 bytes") -static inline float _EvaluateColor( _In_ FXMVECTOR val, _In_ DWORD flags ) -{ - XMFLOAT4A f; - - static XMVECTORF32 lScale = { 0.2125f, 0.7154f, 0.0721f, 1.f }; - - static_assert( CNMAP_CHANNEL_RED == 0x1, "CNMAP_CHANNEL_ flag values don't match mask" ); - switch( flags & 0xf ) + inline float EvaluateColor(_In_ FXMVECTOR val, _In_ DWORD flags) { - case 0: - case CNMAP_CHANNEL_RED: return XMVectorGetX( val ); - case CNMAP_CHANNEL_GREEN: return XMVectorGetY( val ); - case CNMAP_CHANNEL_BLUE: return XMVectorGetZ( val ); - case CNMAP_CHANNEL_ALPHA: return XMVectorGetW( val ); + XMFLOAT4A f; - case CNMAP_CHANNEL_LUMINANCE: + static XMVECTORF32 lScale = { 0.2125f, 0.7154f, 0.0721f, 1.f }; + + static_assert(CNMAP_CHANNEL_RED == 0x1, "CNMAP_CHANNEL_ flag values don't match mask"); + switch (flags & 0xf) { - XMVECTOR v = XMVectorMultiply( val, lScale ); - XMStoreFloat4A( &f, v ); + case 0: + case CNMAP_CHANNEL_RED: return XMVectorGetX(val); + case CNMAP_CHANNEL_GREEN: return XMVectorGetY(val); + case CNMAP_CHANNEL_BLUE: return XMVectorGetZ(val); + case CNMAP_CHANNEL_ALPHA: return XMVectorGetW(val); + + case CNMAP_CHANNEL_LUMINANCE: + { + XMVECTOR v = XMVectorMultiply(val, lScale); + XMStoreFloat4A(&f, v); return f.x + f.y + f.z; } break; - default: - assert(false); - return 0.f; - } -} - -static void _EvaluateRow( _In_reads_(width) const XMVECTOR* pSource, _Out_writes_(width+2) float* pDest, - _In_ size_t width, _In_ DWORD flags ) -{ - assert( pSource && pDest ); - assert( width > 0 ); - - for( size_t x = 0; x < width; ++x ) - { - pDest[x+1] = _EvaluateColor( pSource[x], flags ); + default: + assert(false); + return 0.f; + } } - if ( flags & CNMAP_MIRROR_U ) + void EvaluateRow( + _In_reads_(width) const XMVECTOR* pSource, + _Out_writes_(width + 2) float* pDest, + size_t width, + DWORD flags) { - // Mirror in U - pDest[0] = _EvaluateColor( pSource[0], flags ); - pDest[width+1] = _EvaluateColor( pSource[width-1], flags ); - } - else - { - // Wrap in U - pDest[0] = _EvaluateColor( pSource[width-1], flags ); - pDest[width+1] = _EvaluateColor( pSource[0], flags ); - } -} + assert(pSource && pDest); + assert(width > 0); -static HRESULT _ComputeNMap( _In_ const Image& srcImage, _In_ DWORD flags, _In_ float amplitude, - _In_ DXGI_FORMAT format, _In_ const Image& normalMap ) -{ - if ( !srcImage.pixels || !normalMap.pixels ) - return E_INVALIDARG; - - const DWORD convFlags = _GetConvertFlags( format ); - if ( !convFlags ) - return E_FAIL; - - if ( !( convFlags & (CONVF_UNORM | CONVF_SNORM | CONVF_FLOAT) ) ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); - - const size_t width = srcImage.width; - const size_t height = srcImage.height; - if ( width != normalMap.width || height != normalMap.height ) - return E_FAIL; - - // Allocate temporary space (4 scanlines and 3 evaluated rows) - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( (sizeof(XMVECTOR)*width*4), 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - ScopedAlignedArrayFloat buffer( reinterpret_cast( _aligned_malloc( ( ( sizeof(float) * ( width + 2 ) ) * 3 ), 16 ) ) ); - if ( !buffer ) - return E_OUTOFMEMORY; - - uint8_t* pDest = normalMap.pixels; - if ( !pDest ) - return E_POINTER; - - XMVECTOR* row0 = scanline.get(); - XMVECTOR* row1 = row0 + width; - XMVECTOR* row2 = row1 + width; - XMVECTOR* target = row2 + width; - - float* val0 = buffer.get(); - float* val1 = val0 + width + 2; - float* val2 = val1 + width + 2; - - const size_t rowPitch = srcImage.rowPitch; - const uint8_t* pSrc = srcImage.pixels; - - // Read first scanline row into 'row1' - if ( !_LoadScanline( row1, width, pSrc, rowPitch, srcImage.format ) ) - return E_FAIL; - - // Setup 'row0' - if ( flags & CNMAP_MIRROR_V ) - { - // Mirror first row - memcpy_s( row0, rowPitch, row1, rowPitch ); - } - else - { - // Read last row (Wrap V) - if ( !_LoadScanline( row0, width, pSrc + (rowPitch * (height-1)), rowPitch, srcImage.format ) ) - return E_FAIL; - } - - // Evaluate the initial rows - _EvaluateRow( row0, val0, width, flags ); - _EvaluateRow( row1, val1, width, flags ); - - pSrc += rowPitch; - - for( size_t y = 0; y < height; ++y ) - { - // Load next scanline of source image - if ( y < (height-1) ) + for (size_t x = 0; x < width; ++x) { - if ( !_LoadScanline( row2, width, pSrc, rowPitch, srcImage.format ) ) - return E_FAIL; + pDest[x + 1] = EvaluateColor(pSource[x], flags); + } + + if (flags & CNMAP_MIRROR_U) + { + // Mirror in U + pDest[0] = EvaluateColor(pSource[0], flags); + pDest[width + 1] = EvaluateColor(pSource[width - 1], flags); } else { - if ( flags & CNMAP_MIRROR_V ) + // Wrap in U + pDest[0] = EvaluateColor(pSource[width - 1], flags); + pDest[width + 1] = EvaluateColor(pSource[0], flags); + } + } + + HRESULT ComputeNMap(_In_ const Image& srcImage, _In_ DWORD flags, _In_ float amplitude, + _In_ DXGI_FORMAT format, _In_ const Image& normalMap) + { + if (!srcImage.pixels || !normalMap.pixels) + return E_INVALIDARG; + + const DWORD convFlags = _GetConvertFlags(format); + if (!convFlags) + return E_FAIL; + + if (!(convFlags & (CONVF_UNORM | CONVF_SNORM | CONVF_FLOAT))) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + + const size_t width = srcImage.width; + const size_t height = srcImage.height; + if (width != normalMap.width || height != normalMap.height) + return E_FAIL; + + // Allocate temporary space (4 scanlines and 3 evaluated rows) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc((sizeof(XMVECTOR)*width * 4), 16))); + if (!scanline) + return E_OUTOFMEMORY; + + ScopedAlignedArrayFloat buffer(reinterpret_cast(_aligned_malloc(((sizeof(float) * (width + 2)) * 3), 16))); + if (!buffer) + return E_OUTOFMEMORY; + + uint8_t* pDest = normalMap.pixels; + if (!pDest) + return E_POINTER; + + XMVECTOR* row0 = scanline.get(); + XMVECTOR* row1 = row0 + width; + XMVECTOR* row2 = row1 + width; + XMVECTOR* target = row2 + width; + + float* val0 = buffer.get(); + float* val1 = val0 + width + 2; + float* val2 = val1 + width + 2; + + const size_t rowPitch = srcImage.rowPitch; + const uint8_t* pSrc = srcImage.pixels; + + // Read first scanline row into 'row1' + if (!_LoadScanline(row1, width, pSrc, rowPitch, srcImage.format)) + return E_FAIL; + + // Setup 'row0' + if (flags & CNMAP_MIRROR_V) + { + // Mirror first row + memcpy_s(row0, rowPitch, row1, rowPitch); + } + else + { + // Read last row (Wrap V) + if (!_LoadScanline(row0, width, pSrc + (rowPitch * (height - 1)), rowPitch, srcImage.format)) + return E_FAIL; + } + + // Evaluate the initial rows + EvaluateRow(row0, val0, width, flags); + EvaluateRow(row1, val1, width, flags); + + pSrc += rowPitch; + + for (size_t y = 0; y < height; ++y) + { + // Load next scanline of source image + if (y < (height - 1)) { - // Use last row of source image - if ( !_LoadScanline( row2, width, srcImage.pixels + (rowPitch * (height-1)), rowPitch, srcImage.format ) ) + if (!_LoadScanline(row2, width, pSrc, rowPitch, srcImage.format)) return E_FAIL; } else { - // Use first row of source image (Wrap V) - if ( !_LoadScanline( row2, width, srcImage.pixels, rowPitch, srcImage.format ) ) - return E_FAIL; - } - } - - // Evaluate row - _EvaluateRow( row2, val2, width, flags ); - - // Generate target scanline - XMVECTOR *dptr = target; - for( size_t x = 0; x < width; ++x ) - { - // Compute normal via central differencing - float totDelta = ( val0[x] - val0[x+2] ) + ( val1[x] - val1[x+2] ) + ( val2[x] - val2[x+2] ); - float deltaZX = totDelta * amplitude / 6.f; - - totDelta = ( val0[x] - val2[x] ) + ( val0[x+1] - val2[x+1] ) + ( val0[x+2] - val2[x+2] ); - float deltaZY = totDelta * amplitude / 6.f; - - XMVECTOR vx = XMVectorSetZ( g_XMNegIdentityR0, deltaZX ); // (-1.0f, 0.0f, deltaZX) - XMVECTOR vy = XMVectorSetZ( g_XMNegIdentityR1, deltaZY ); // (0.0f, -1.0f, deltaZY) - - XMVECTOR normal = XMVector3Normalize( XMVector3Cross( vx, vy ) ); - - // Compute alpha (1.0 or an occlusion term) - float alpha = 1.f; - - if ( flags & CNMAP_COMPUTE_OCCLUSION ) - { - float delta = 0.f; - float c = val1[x+1]; - - float t = val0[x] - c; if ( t > 0.f ) delta += t; - t = val0[x+1] - c; if ( t > 0.f ) delta += t; - t = val0[x+2] - c; if ( t > 0.f ) delta += t; - t = val1[x] - c; if ( t > 0.f ) delta += t; - // Skip current pixel - t = val1[x+2] - c; if ( t > 0.f ) delta += t; - t = val2[x] - c; if ( t > 0.f ) delta += t; - t = val2[x+1] - c; if ( t > 0.f ) delta += t; - t = val2[x+2] - c; if ( t > 0.f ) delta += t; - - // Average delta (divide by 8, scale by amplitude factor) - delta *= 0.125f * amplitude; - if ( delta > 0.f ) + if (flags & CNMAP_MIRROR_V) { - // If < 0, then no occlusion - float r = sqrtf( 1.f + delta*delta ); - alpha = (r - delta) / r; + // Use last row of source image + if (!_LoadScanline(row2, width, srcImage.pixels + (rowPitch * (height - 1)), rowPitch, srcImage.format)) + return E_FAIL; + } + else + { + // Use first row of source image (Wrap V) + if (!_LoadScanline(row2, width, srcImage.pixels, rowPitch, srcImage.format)) + return E_FAIL; } } - // Encode based on target format - if ( convFlags & CONVF_UNORM ) + // Evaluate row + EvaluateRow(row2, val2, width, flags); + + // Generate target scanline + XMVECTOR *dptr = target; + for (size_t x = 0; x < width; ++x) { - // 0.5f*normal + 0.5f -or- invert sign case: -0.5f*normal + 0.5f - XMVECTOR n1 = XMVectorMultiplyAdd( (flags & CNMAP_INVERT_SIGN) ? g_XMNegativeOneHalf : g_XMOneHalf, normal, g_XMOneHalf ); - *dptr++ = XMVectorSetW( n1, alpha ); - } - else if ( flags & CNMAP_INVERT_SIGN ) - { - *dptr++ = XMVectorSetW( XMVectorNegate( normal ), alpha ); - } - else - { - *dptr++ = XMVectorSetW( normal, alpha ); + // Compute normal via central differencing + float totDelta = (val0[x] - val0[x + 2]) + (val1[x] - val1[x + 2]) + (val2[x] - val2[x + 2]); + float deltaZX = totDelta * amplitude / 6.f; + + totDelta = (val0[x] - val2[x]) + (val0[x + 1] - val2[x + 1]) + (val0[x + 2] - val2[x + 2]); + float deltaZY = totDelta * amplitude / 6.f; + + XMVECTOR vx = XMVectorSetZ(g_XMNegIdentityR0, deltaZX); // (-1.0f, 0.0f, deltaZX) + XMVECTOR vy = XMVectorSetZ(g_XMNegIdentityR1, deltaZY); // (0.0f, -1.0f, deltaZY) + + XMVECTOR normal = XMVector3Normalize(XMVector3Cross(vx, vy)); + + // Compute alpha (1.0 or an occlusion term) + float alpha = 1.f; + + if (flags & CNMAP_COMPUTE_OCCLUSION) + { + float delta = 0.f; + float c = val1[x + 1]; + + float t = val0[x] - c; if (t > 0.f) delta += t; + t = val0[x + 1] - c; if (t > 0.f) delta += t; + t = val0[x + 2] - c; if (t > 0.f) delta += t; + t = val1[x] - c; if (t > 0.f) delta += t; + // Skip current pixel + t = val1[x + 2] - c; if (t > 0.f) delta += t; + t = val2[x] - c; if (t > 0.f) delta += t; + t = val2[x + 1] - c; if (t > 0.f) delta += t; + t = val2[x + 2] - c; if (t > 0.f) delta += t; + + // Average delta (divide by 8, scale by amplitude factor) + delta *= 0.125f * amplitude; + if (delta > 0.f) + { + // If < 0, then no occlusion + float r = sqrtf(1.f + delta*delta); + alpha = (r - delta) / r; + } + } + + // Encode based on target format + if (convFlags & CONVF_UNORM) + { + // 0.5f*normal + 0.5f -or- invert sign case: -0.5f*normal + 0.5f + XMVECTOR n1 = XMVectorMultiplyAdd((flags & CNMAP_INVERT_SIGN) ? g_XMNegativeOneHalf : g_XMOneHalf, normal, g_XMOneHalf); + *dptr++ = XMVectorSetW(n1, alpha); + } + else if (flags & CNMAP_INVERT_SIGN) + { + *dptr++ = XMVectorSetW(XMVectorNegate(normal), alpha); + } + else + { + *dptr++ = XMVectorSetW(normal, alpha); + } } + + if (!_StoreScanline(pDest, normalMap.rowPitch, format, target, width)) + return E_FAIL; + + // Cycle buffers + float* temp = val0; + val0 = val1; + val1 = val2; + val2 = temp; + + pSrc += rowPitch; + pDest += normalMap.rowPitch; } - if ( !_StoreScanline( pDest, normalMap.rowPitch, format, target, width ) ) - return E_FAIL; - - // Cycle buffers - float* temp = val0; - val0 = val1; - val1 = val2; - val2 = temp; - - pSrc += rowPitch; - pDest += normalMap.rowPitch; + return S_OK; } - - return S_OK; } @@ -252,14 +258,18 @@ static HRESULT _ComputeNMap( _In_ const Image& srcImage, _In_ DWORD flags, _In_ // Generates a normal map from a height-map //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT ComputeNormalMap( const Image& srcImage, DWORD flags, float amplitude, - DXGI_FORMAT format, ScratchImage& normalMap ) +HRESULT DirectX::ComputeNormalMap( + const Image& srcImage, + DWORD flags, + float amplitude, + DXGI_FORMAT format, + ScratchImage& normalMap) { - if ( !srcImage.pixels || !IsValid(format) ) + if (!srcImage.pixels || !IsValid(format)) return E_INVALIDARG; - static_assert( CNMAP_CHANNEL_RED == 0x1, "CNMAP_CHANNEL_ flag values don't match mask" ); - switch( flags & 0xf ) + static_assert(CNMAP_CHANNEL_RED == 0x1, "CNMAP_CHANNEL_ flag values don't match mask"); + switch (flags & 0xf) { case 0: case CNMAP_CHANNEL_RED: @@ -273,28 +283,28 @@ HRESULT ComputeNormalMap( const Image& srcImage, DWORD flags, float amplitude, return E_INVALIDARG; } - 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 ); + 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 normalMap.Release(); - HRESULT hr = normalMap.Initialize2D( format, srcImage.width, srcImage.height, 1, 1 ); - if ( FAILED(hr) ) + HRESULT hr = normalMap.Initialize2D(format, srcImage.width, srcImage.height, 1, 1); + if (FAILED(hr)) return hr; - const Image *img = normalMap.GetImage( 0, 0, 0 ); - if ( !img ) + const Image *img = normalMap.GetImage(0, 0, 0); + if (!img) { normalMap.Release(); return E_POINTER; } - hr = _ComputeNMap( srcImage, flags, amplitude, format, *img ); - if ( FAILED(hr) ) + hr = ComputeNMap(srcImage, flags, amplitude, format, *img); + if (FAILED(hr)) { normalMap.Release(); return hr; @@ -304,20 +314,26 @@ HRESULT ComputeNormalMap( const Image& srcImage, DWORD flags, float amplitude, } _Use_decl_annotations_ -HRESULT ComputeNormalMap( const Image* srcImages, size_t nimages, const TexMetadata& metadata, - DWORD flags, float amplitude, DXGI_FORMAT format, ScratchImage& normalMaps ) +HRESULT DirectX::ComputeNormalMap( + const Image* srcImages, + size_t nimages, + const TexMetadata& metadata, + DWORD flags, + float amplitude, + DXGI_FORMAT format, + ScratchImage& normalMaps) { - if ( !srcImages || !nimages || !IsValid(format) ) + if (!srcImages || !nimages || !IsValid(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 ); + 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 ) + static_assert(CNMAP_CHANNEL_RED == 0x1, "CNMAP_CHANNEL_ flag values don't match mask"); + switch (flags & 0xf) { case 0: case CNMAP_CHANNEL_RED: @@ -335,42 +351,42 @@ HRESULT ComputeNormalMap( const Image* srcImages, size_t nimages, const TexMetad TexMetadata mdata2 = metadata; mdata2.format = format; - HRESULT hr = normalMaps.Initialize( mdata2 ); - if ( FAILED(hr) ) + HRESULT hr = normalMaps.Initialize(mdata2); + if (FAILED(hr)) return hr; - if ( nimages != normalMaps.GetImageCount() ) + if (nimages != normalMaps.GetImageCount()) { normalMaps.Release(); return E_FAIL; } const Image* dest = normalMaps.GetImages(); - if ( !dest ) + if (!dest) { normalMaps.Release(); return E_POINTER; } - for( size_t index=0; index < nimages; ++index ) + for (size_t index = 0; index < nimages; ++index) { - assert( dest[ index ].format == format ); + assert(dest[index].format == format); - const Image& src = srcImages[ index ]; - if ( IsCompressed( src.format ) || IsTypeless( src.format ) ) + const Image& src = srcImages[index]; + if (IsCompressed(src.format) || IsTypeless(src.format)) { normalMaps.Release(); - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } - if ( src.width != dest[ index ].width || src.height != dest[ index ].height ) + if (src.width != dest[index].width || src.height != dest[index].height) { normalMaps.Release(); return E_FAIL; } - hr = _ComputeNMap( src, flags, amplitude, format, dest[ index ] ); - if ( FAILED(hr) ) + hr = ComputeNMap(src, flags, amplitude, format, dest[index]); + if (FAILED(hr)) { normalMaps.Release(); return hr; @@ -379,5 +395,3 @@ HRESULT ComputeNormalMap( const Image* srcImages, size_t nimages, const TexMetad return S_OK; } - -}; // namespace diff --git a/DirectXTex/DirectXTexP.h b/DirectXTex/DirectXTexP.h index 269c11d..ab98f10 100644 --- a/DirectXTex/DirectXTexP.h +++ b/DirectXTex/DirectXTexP.h @@ -175,40 +175,40 @@ namespace DirectX void __cdecl _CopyScanline( _When_(pDestination == pSource, _Inout_updates_bytes_(outSize)) _When_(pDestination != pSource, _Out_writes_bytes_(outSize)) - LPVOID pDestination, _In_ size_t outSize, - _In_reads_bytes_(inSize) LPCVOID pSource, _In_ size_t inSize, + void* pDestination, _In_ size_t outSize, + _In_reads_bytes_(inSize) const void* pSource, _In_ size_t inSize, _In_ DXGI_FORMAT format, _In_ DWORD flags ); void __cdecl _SwizzleScanline( _When_(pDestination == pSource, _In_) _When_(pDestination != pSource, _Out_writes_bytes_(outSize)) - LPVOID pDestination, _In_ size_t outSize, - _In_reads_bytes_(inSize) LPCVOID pSource, _In_ size_t inSize, + void* pDestination, _In_ size_t outSize, + _In_reads_bytes_(inSize) const void* pSource, _In_ size_t inSize, _In_ DXGI_FORMAT format, _In_ DWORD flags ); _Success_(return != false) - bool __cdecl _ExpandScanline( _Out_writes_bytes_(outSize) LPVOID pDestination, _In_ size_t outSize, + bool __cdecl _ExpandScanline( _Out_writes_bytes_(outSize) void* pDestination, _In_ size_t outSize, _In_ DXGI_FORMAT outFormat, - _In_reads_bytes_(inSize) LPCVOID pSource, _In_ size_t inSize, + _In_reads_bytes_(inSize) const void* pSource, _In_ size_t inSize, _In_ DXGI_FORMAT inFormat, _In_ DWORD flags ); _Success_(return != false) bool __cdecl _LoadScanline( _Out_writes_(count) XMVECTOR* pDestination, _In_ size_t count, - _In_reads_bytes_(size) LPCVOID pSource, _In_ size_t size, _In_ DXGI_FORMAT format ); + _In_reads_bytes_(size) const void* pSource, _In_ size_t size, _In_ DXGI_FORMAT format ); _Success_(return != false) bool __cdecl _LoadScanlineLinear( _Out_writes_(count) XMVECTOR* pDestination, _In_ size_t count, - _In_reads_bytes_(size) LPCVOID pSource, _In_ size_t size, _In_ DXGI_FORMAT format, _In_ DWORD flags ); + _In_reads_bytes_(size) const void* pSource, _In_ size_t size, _In_ DXGI_FORMAT format, _In_ DWORD flags ); _Success_(return != false) - bool __cdecl _StoreScanline( LPVOID pDestination, _In_ size_t size, _In_ DXGI_FORMAT format, + bool __cdecl _StoreScanline( void* pDestination, _In_ size_t size, _In_ DXGI_FORMAT format, _In_reads_(count) const XMVECTOR* pSource, _In_ size_t count, _In_ float threshold = 0 ); _Success_(return != false) - bool __cdecl _StoreScanlineLinear( LPVOID pDestination, _In_ size_t size, _In_ DXGI_FORMAT format, + bool __cdecl _StoreScanlineLinear( void* pDestination, _In_ size_t size, _In_ DXGI_FORMAT format, _Inout_updates_all_(count) XMVECTOR* pSource, _In_ size_t count, _In_ DWORD flags, _In_ float threshold = 0 ); _Success_(return != false) - bool __cdecl _StoreScanlineDither( LPVOID pDestination, _In_ size_t size, _In_ DXGI_FORMAT format, + bool __cdecl _StoreScanlineDither( void* pDestination, _In_ size_t size, _In_ DXGI_FORMAT format, _Inout_updates_all_(count) XMVECTOR* pSource, _In_ size_t count, _In_ float threshold, size_t y, size_t z, _Inout_updates_all_opt_(count+2) XMVECTOR* pDiffusionErrors ); @@ -225,6 +225,6 @@ namespace DirectX //--------------------------------------------------------------------------------- // DDS helper functions HRESULT __cdecl _EncodeDDSHeader( _In_ const TexMetadata& metadata, DWORD flags, - _Out_writes_bytes_to_opt_(maxsize, required) LPVOID pDestination, _In_ size_t maxsize, _Out_ size_t& required ); + _Out_writes_bytes_to_opt_(maxsize, required) void* pDestination, _In_ size_t maxsize, _Out_ size_t& required ); }; // namespace diff --git a/DirectXTex/DirectXTexPMAlpha.cpp b/DirectXTex/DirectXTexPMAlpha.cpp index 4d34022..633c154 100644 --- a/DirectXTex/DirectXTexPMAlpha.cpp +++ b/DirectXTex/DirectXTexPMAlpha.cpp @@ -15,88 +15,91 @@ #include "directxtexp.h" -namespace DirectX +using namespace DirectX; + +namespace { -static HRESULT _PremultiplyAlpha( _In_ const Image& srcImage, _In_ const Image& destImage ) -{ - assert( srcImage.width == destImage.width ); - assert( srcImage.height == destImage.height ); - - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( (sizeof(XMVECTOR)*srcImage.width), 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - const uint8_t *pSrc = srcImage.pixels; - uint8_t *pDest = destImage.pixels; - if ( !pSrc || !pDest ) - return E_POINTER; - - for( size_t h = 0; h < srcImage.height; ++h ) + HRESULT PremultiplyAlpha_(const Image& srcImage, const Image& destImage) { - if ( !_LoadScanline( scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) ) - return E_FAIL; + assert(srcImage.width == destImage.width); + assert(srcImage.height == destImage.height); - XMVECTOR* ptr = scanline.get(); - for( size_t w = 0; w < srcImage.width; ++w ) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc((sizeof(XMVECTOR)*srcImage.width), 16))); + if (!scanline) + return E_OUTOFMEMORY; + + const uint8_t *pSrc = srcImage.pixels; + uint8_t *pDest = destImage.pixels; + if (!pSrc || !pDest) + return E_POINTER; + + for (size_t h = 0; h < srcImage.height; ++h) { - XMVECTOR v = *ptr; - XMVECTOR alpha = XMVectorSplatW( *ptr ); - alpha = XMVectorMultiply( v, alpha ); - *(ptr++) = XMVectorSelect( v, alpha, g_XMSelect1110 ); + if (!_LoadScanline(scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format)) + return E_FAIL; + + XMVECTOR* ptr = scanline.get(); + for (size_t w = 0; w < srcImage.width; ++w) + { + XMVECTOR v = *ptr; + XMVECTOR alpha = XMVectorSplatW(*ptr); + alpha = XMVectorMultiply(v, alpha); + *(ptr++) = XMVectorSelect(v, alpha, g_XMSelect1110); + } + + if (!_StoreScanline(pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width)) + return E_FAIL; + + pSrc += srcImage.rowPitch; + pDest += destImage.rowPitch; } - if ( !_StoreScanline( pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width ) ) - return E_FAIL; - - pSrc += srcImage.rowPitch; - pDest += destImage.rowPitch; + return S_OK; } - return S_OK; -} - -static HRESULT _PremultiplyAlphaLinear( _In_ const Image& srcImage, _In_ DWORD flags, _In_ const Image& destImage ) -{ - assert( srcImage.width == destImage.width ); - assert( srcImage.height == destImage.height ); - - static_assert( TEX_PMALPHA_SRGB_IN == TEX_FILTER_SRGB_IN, "TEX_PMALHPA_SRGB* should match TEX_FILTER_SRGB*" ); - static_assert( TEX_PMALPHA_SRGB_OUT == TEX_FILTER_SRGB_OUT, "TEX_PMALHPA_SRGB* should match TEX_FILTER_SRGB*" ); - static_assert( TEX_PMALPHA_SRGB == TEX_FILTER_SRGB, "TEX_PMALHPA_SRGB* should match TEX_FILTER_SRGB*" ); - flags &= TEX_PMALPHA_SRGB; - - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( (sizeof(XMVECTOR)*srcImage.width), 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - const uint8_t *pSrc = srcImage.pixels; - uint8_t *pDest = destImage.pixels; - if ( !pSrc || !pDest ) - return E_POINTER; - - for( size_t h = 0; h < srcImage.height; ++h ) + HRESULT PremultiplyAlphaLinear(const Image& srcImage, DWORD flags, const Image& destImage) { - if ( !_LoadScanlineLinear( scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format, flags ) ) - return E_FAIL; + assert(srcImage.width == destImage.width); + assert(srcImage.height == destImage.height); - XMVECTOR* ptr = scanline.get(); - for( size_t w = 0; w < srcImage.width; ++w ) + static_assert(TEX_PMALPHA_SRGB_IN == TEX_FILTER_SRGB_IN, "TEX_PMALHPA_SRGB* should match TEX_FILTER_SRGB*"); + static_assert(TEX_PMALPHA_SRGB_OUT == TEX_FILTER_SRGB_OUT, "TEX_PMALHPA_SRGB* should match TEX_FILTER_SRGB*"); + static_assert(TEX_PMALPHA_SRGB == TEX_FILTER_SRGB, "TEX_PMALHPA_SRGB* should match TEX_FILTER_SRGB*"); + flags &= TEX_PMALPHA_SRGB; + + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc((sizeof(XMVECTOR)*srcImage.width), 16))); + if (!scanline) + return E_OUTOFMEMORY; + + const uint8_t *pSrc = srcImage.pixels; + uint8_t *pDest = destImage.pixels; + if (!pSrc || !pDest) + return E_POINTER; + + for (size_t h = 0; h < srcImage.height; ++h) { - XMVECTOR v = *ptr; - XMVECTOR alpha = XMVectorSplatW( *ptr ); - alpha = XMVectorMultiply( v, alpha ); - *(ptr++) = XMVectorSelect( v, alpha, g_XMSelect1110 ); + if (!_LoadScanlineLinear(scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format, flags)) + return E_FAIL; + + XMVECTOR* ptr = scanline.get(); + for (size_t w = 0; w < srcImage.width; ++w) + { + XMVECTOR v = *ptr; + XMVECTOR alpha = XMVectorSplatW(*ptr); + alpha = XMVectorMultiply(v, alpha); + *(ptr++) = XMVectorSelect(v, alpha, g_XMSelect1110); + } + + if (!_StoreScanlineLinear(pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width, flags)) + return E_FAIL; + + pSrc += srcImage.rowPitch; + pDest += destImage.rowPitch; } - if ( !_StoreScanlineLinear( pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width, flags ) ) - return E_FAIL; - - pSrc += srcImage.rowPitch; - pDest += destImage.rowPitch; + return S_OK; } - - return S_OK; } @@ -108,34 +111,37 @@ static HRESULT _PremultiplyAlphaLinear( _In_ const Image& srcImage, _In_ DWORD f // Converts to a premultiplied alpha version of the texture //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT PremultiplyAlpha( const Image& srcImage, DWORD flags, ScratchImage& image ) +HRESULT DirectX::PremultiplyAlpha( + const Image& srcImage, + DWORD flags, + ScratchImage& image) { - if ( !srcImage.pixels ) + if (!srcImage.pixels) return E_POINTER; - if ( IsCompressed(srcImage.format) - || IsPlanar(srcImage.format) - || IsPalettized(srcImage.format) - || IsTypeless(srcImage.format) - || !HasAlpha(srcImage.format) ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if (IsCompressed(srcImage.format) + || IsPlanar(srcImage.format) + || IsPalettized(srcImage.format) + || IsTypeless(srcImage.format) + || !HasAlpha(srcImage.format)) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); - if ( (srcImage.width > UINT32_MAX) || (srcImage.height > UINT32_MAX) ) + if ((srcImage.width > UINT32_MAX) || (srcImage.height > UINT32_MAX)) return E_INVALIDARG; - HRESULT hr = image.Initialize2D( srcImage.format, srcImage.width, srcImage.height, 1, 1 ); - if ( FAILED(hr) ) + HRESULT hr = image.Initialize2D(srcImage.format, srcImage.width, srcImage.height, 1, 1); + if (FAILED(hr)) return hr; - - const Image *rimage = image.GetImage( 0, 0, 0 ); - if ( !rimage ) + + const Image *rimage = image.GetImage(0, 0, 0); + if (!rimage) { image.Release(); return E_POINTER; } - hr = ( flags & TEX_PMALPHA_IGNORE_SRGB ) ? _PremultiplyAlpha( srcImage, *rimage ) : _PremultiplyAlphaLinear( srcImage, flags, *rimage ); - if ( FAILED(hr) ) + hr = (flags & TEX_PMALPHA_IGNORE_SRGB) ? PremultiplyAlpha_(srcImage, *rimage) : PremultiplyAlphaLinear(srcImage, flags, *rimage); + if (FAILED(hr)) { image.Release(); return hr; @@ -149,22 +155,27 @@ HRESULT PremultiplyAlpha( const Image& srcImage, DWORD flags, ScratchImage& imag // Converts to a premultiplied alpha version of the texture (complex) //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT PremultiplyAlpha( const Image* srcImages, size_t nimages, const TexMetadata& metadata, DWORD flags, ScratchImage& result ) +HRESULT DirectX::PremultiplyAlpha( + const Image* srcImages, + size_t nimages, + const TexMetadata& metadata, + DWORD flags, + ScratchImage& result) { - if ( !srcImages || !nimages ) + if (!srcImages || !nimages) return E_INVALIDARG; - if ( IsCompressed(metadata.format) - || IsPlanar(metadata.format) - || IsPalettized(metadata.format) - || IsTypeless(metadata.format) - || !HasAlpha(metadata.format) ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + if (IsCompressed(metadata.format) + || IsPlanar(metadata.format) + || IsPalettized(metadata.format) + || IsTypeless(metadata.format) + || !HasAlpha(metadata.format)) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); - if ( (metadata.width > UINT32_MAX) || (metadata.height > UINT32_MAX) ) + if ((metadata.width > UINT32_MAX) || (metadata.height > UINT32_MAX)) return E_INVALIDARG; - if ( metadata.IsPMAlpha() ) + if (metadata.IsPMAlpha()) { // Already premultiplied return E_FAIL; @@ -172,46 +183,46 @@ HRESULT PremultiplyAlpha( const Image* srcImages, size_t nimages, const TexMetad TexMetadata mdata2 = metadata; mdata2.SetAlphaMode(TEX_ALPHA_MODE_PREMULTIPLIED); - HRESULT hr = result.Initialize( mdata2 ); - if ( FAILED(hr) ) + HRESULT hr = result.Initialize(mdata2); + if (FAILED(hr)) return hr; - if ( nimages != result.GetImageCount() ) + if (nimages != result.GetImageCount()) { result.Release(); return E_FAIL; } const Image* dest = result.GetImages(); - if ( !dest ) + if (!dest) { result.Release(); return E_POINTER; } - for( size_t index=0; index < nimages; ++index ) + for (size_t index = 0; index < nimages; ++index) { - const Image& src = srcImages[ index ]; - if ( src.format != metadata.format ) + const Image& src = srcImages[index]; + if (src.format != metadata.format) { result.Release(); return E_FAIL; } - if ( (src.width > UINT32_MAX) || (src.height > UINT32_MAX) ) + if ((src.width > UINT32_MAX) || (src.height > UINT32_MAX)) return E_FAIL; - const Image& dst = dest[ index ]; - assert( dst.format == metadata.format ); + const Image& dst = dest[index]; + assert(dst.format == metadata.format); - if ( src.width != dst.width || src.height != dst.height ) + if (src.width != dst.width || src.height != dst.height) { result.Release(); return E_FAIL; } - hr = ( flags & TEX_PMALPHA_IGNORE_SRGB ) ? _PremultiplyAlpha( src, dst ) : _PremultiplyAlphaLinear( src, flags, dst ); - if ( FAILED(hr) ) + hr = (flags & TEX_PMALPHA_IGNORE_SRGB) ? PremultiplyAlpha_(src, dst) : PremultiplyAlphaLinear(src, flags, dst); + if (FAILED(hr)) { result.Release(); return hr; @@ -220,5 +231,3 @@ HRESULT PremultiplyAlpha( const Image* srcImages, size_t nimages, const TexMetad return S_OK; } - -}; // namespace diff --git a/DirectXTex/DirectXTexResize.cpp b/DirectXTex/DirectXTexResize.cpp index 9709eeb..b6e3ca9 100644 --- a/DirectXTex/DirectXTexResize.cpp +++ b/DirectXTex/DirectXTexResize.cpp @@ -17,805 +17,811 @@ #include "filters.h" +using namespace DirectX; using Microsoft::WRL::ComPtr; namespace DirectX { + extern HRESULT _ResizeSeparateColorAndAlpha(_In_ IWICImagingFactory* pWIC, _In_ bool iswic2, _In_ IWICBitmap* original, + _In_ size_t newWidth, _In_ size_t newHeight, _In_ DWORD filter, _Inout_ const Image* img); +} -//------------------------------------------------------------------------------------- -// WIC related helper functions -//------------------------------------------------------------------------------------- - -extern HRESULT _ResizeSeparateColorAndAlpha( _In_ IWICImagingFactory* pWIC, _In_ bool iswic2, _In_ IWICBitmap* original, - _In_ size_t newWidth, _In_ size_t newHeight, _In_ DWORD filter, _Inout_ const Image* img ); - -//--- Do image resize using WIC --- -static HRESULT _PerformResizeUsingWIC( _In_ const Image& srcImage, _In_ DWORD filter, - _In_ const WICPixelFormatGUID& pfGUID, _In_ const Image& destImage ) +namespace { - if ( !srcImage.pixels || !destImage.pixels ) - return E_POINTER; - - assert( srcImage.format == destImage.format ); - - bool iswic2 = false; - IWICImagingFactory* pWIC = GetWICFactory(iswic2); - if ( !pWIC ) - return E_NOINTERFACE; - - ComPtr componentInfo; - HRESULT hr = pWIC->CreateComponentInfo( pfGUID, componentInfo.GetAddressOf() ); - if ( FAILED(hr) ) - return hr; - - ComPtr pixelFormatInfo; - hr = componentInfo.As( &pixelFormatInfo ); - if ( FAILED(hr) ) - return hr; - - BOOL supportsTransparency = FALSE; - hr = pixelFormatInfo->SupportsTransparency( &supportsTransparency ); - if ( FAILED(hr) ) - return hr; - - ComPtr source; - hr = pWIC->CreateBitmapFromMemory( static_cast( srcImage.width ), static_cast( srcImage.height ), pfGUID, - static_cast( srcImage.rowPitch ), static_cast( srcImage.slicePitch ), - srcImage.pixels, source.GetAddressOf() ); - if ( FAILED(hr) ) - return hr; - - if ( (filter & TEX_FILTER_SEPARATE_ALPHA) && supportsTransparency ) + //--- Do image resize using WIC --- + HRESULT PerformResizeUsingWIC( + const Image& srcImage, + DWORD filter, + const WICPixelFormatGUID& pfGUID, + const Image& destImage) { - hr = _ResizeSeparateColorAndAlpha( pWIC, iswic2, source.Get(), destImage.width, destImage.height, filter, &destImage ); - if ( FAILED(hr) ) - return hr; - } - else - { - ComPtr scaler; - hr = pWIC->CreateBitmapScaler( scaler.GetAddressOf() ); - if ( FAILED(hr) ) + if (!srcImage.pixels || !destImage.pixels) + return E_POINTER; + + assert(srcImage.format == destImage.format); + + bool iswic2 = false; + IWICImagingFactory* pWIC = GetWICFactory(iswic2); + if (!pWIC) + return E_NOINTERFACE; + + ComPtr componentInfo; + HRESULT hr = pWIC->CreateComponentInfo(pfGUID, componentInfo.GetAddressOf()); + if (FAILED(hr)) return hr; - hr = scaler->Initialize( source.Get(), static_cast( destImage.width ), static_cast( destImage.height ), _GetWICInterp( filter ) ); - if ( FAILED(hr) ) + ComPtr pixelFormatInfo; + hr = componentInfo.As(&pixelFormatInfo); + if (FAILED(hr)) return hr; - WICPixelFormatGUID pfScaler; - hr = scaler->GetPixelFormat( &pfScaler ); - if ( FAILED(hr) ) + BOOL supportsTransparency = FALSE; + hr = pixelFormatInfo->SupportsTransparency(&supportsTransparency); + if (FAILED(hr)) return hr; - if ( memcmp( &pfScaler, &pfGUID, sizeof(WICPixelFormatGUID) ) == 0 ) + ComPtr source; + hr = pWIC->CreateBitmapFromMemory(static_cast(srcImage.width), static_cast(srcImage.height), pfGUID, + static_cast(srcImage.rowPitch), static_cast(srcImage.slicePitch), + srcImage.pixels, source.GetAddressOf()); + if (FAILED(hr)) + return hr; + + if ((filter & TEX_FILTER_SEPARATE_ALPHA) && supportsTransparency) { - hr = scaler->CopyPixels( 0, static_cast( destImage.rowPitch ), static_cast( destImage.slicePitch ), destImage.pixels ); - if ( FAILED(hr) ) + hr = _ResizeSeparateColorAndAlpha(pWIC, iswic2, source.Get(), destImage.width, destImage.height, filter, &destImage); + if (FAILED(hr)) return hr; } else { - // The WIC bitmap scaler is free to return a different pixel format than the source image, so here we - // convert it back - ComPtr FC; - hr = pWIC->CreateFormatConverter( FC.GetAddressOf() ); - if ( FAILED(hr) ) + ComPtr scaler; + hr = pWIC->CreateBitmapScaler(scaler.GetAddressOf()); + if (FAILED(hr)) return hr; - BOOL canConvert = FALSE; - hr = FC->CanConvert( pfScaler, pfGUID, &canConvert ); - if ( FAILED(hr) || !canConvert ) + hr = scaler->Initialize(source.Get(), static_cast(destImage.width), static_cast(destImage.height), _GetWICInterp(filter)); + if (FAILED(hr)) + return hr; + + WICPixelFormatGUID pfScaler; + hr = scaler->GetPixelFormat(&pfScaler); + if (FAILED(hr)) + return hr; + + if (memcmp(&pfScaler, &pfGUID, sizeof(WICPixelFormatGUID)) == 0) { - return E_UNEXPECTED; + hr = scaler->CopyPixels(0, static_cast(destImage.rowPitch), static_cast(destImage.slicePitch), destImage.pixels); + if (FAILED(hr)) + return hr; + } + else + { + // The WIC bitmap scaler is free to return a different pixel format than the source image, so here we + // convert it back + ComPtr FC; + hr = pWIC->CreateFormatConverter(FC.GetAddressOf()); + if (FAILED(hr)) + return hr; + + BOOL canConvert = FALSE; + hr = FC->CanConvert(pfScaler, pfGUID, &canConvert); + if (FAILED(hr) || !canConvert) + { + return E_UNEXPECTED; + } + + hr = FC->Initialize(scaler.Get(), pfGUID, _GetWICDither(filter), 0, 0, WICBitmapPaletteTypeCustom); + if (FAILED(hr)) + return hr; + + hr = FC->CopyPixels(0, static_cast(destImage.rowPitch), static_cast(destImage.slicePitch), destImage.pixels); + if (FAILED(hr)) + return hr; + } + } + + return S_OK; + } + + + //--- Do conversion, resize using WIC, conversion cycle --- + HRESULT PerformResizeViaF32( + const Image& srcImage, + DWORD filter, + const Image& destImage) + { + if (!srcImage.pixels || !destImage.pixels) + return E_POINTER; + + assert(srcImage.format != DXGI_FORMAT_R32G32B32A32_FLOAT); + assert(srcImage.format == destImage.format); + + ScratchImage temp; + HRESULT hr = _ConvertToR32G32B32A32(srcImage, temp); + if (FAILED(hr)) + return hr; + + const Image *tsrc = temp.GetImage(0, 0, 0); + if (!tsrc) + return E_POINTER; + + ScratchImage rtemp; + hr = rtemp.Initialize2D(DXGI_FORMAT_R32G32B32A32_FLOAT, destImage.width, destImage.height, 1, 1); + if (FAILED(hr)) + return hr; + + const Image *tdest = rtemp.GetImage(0, 0, 0); + if (!tdest) + return E_POINTER; + + hr = PerformResizeUsingWIC(*tsrc, filter, GUID_WICPixelFormat128bppRGBAFloat, *tdest); + if (FAILED(hr)) + return hr; + + temp.Release(); + + hr = _ConvertFromR32G32B32A32(*tdest, destImage); + if (FAILED(hr)) + return hr; + + return S_OK; + } + + + //--- determine when to use WIC vs. non-WIC paths --- + bool UseWICFiltering(_In_ DXGI_FORMAT format, _In_ DWORD filter) + { + if (filter & TEX_FILTER_FORCE_NON_WIC) + { + // Explicit flag indicates use of non-WIC code paths + return false; + } + + if (filter & TEX_FILTER_FORCE_WIC) + { + // Explicit flag to use WIC code paths, skips all the case checks below + return true; + } + + if (IsSRGB(format) || (filter & TEX_FILTER_SRGB)) + { + // Use non-WIC code paths for sRGB correct filtering + return false; + } + +#if defined(_XBOX_ONE) && defined(_TITLE) + if (format == DXGI_FORMAT_R16G16B16A16_FLOAT + || format == DXGI_FORMAT_R16_FLOAT) + { + // Use non-WIC code paths as these conversions are not supported by Xbox One XDK + return false; + } +#endif + + static_assert(TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK"); + + switch (filter & TEX_FILTER_MASK) + { + case TEX_FILTER_LINEAR: + if (filter & TEX_FILTER_WRAP) + { + // WIC only supports 'clamp' semantics (MIRROR is equivalent to clamp for linear) + return false; } - hr = FC->Initialize( scaler.Get(), pfGUID, _GetWICDither( filter ), 0, 0, WICBitmapPaletteTypeCustom ); - if ( FAILED(hr) ) - return hr; + if (BitsPerColor(format) > 8) + { + // Avoid the WIC bitmap scaler when doing Linear filtering of XR/HDR formats + return false; + } + break; - hr = FC->CopyPixels( 0, static_cast( destImage.rowPitch ), static_cast( destImage.slicePitch ), destImage.pixels ); - if ( FAILED(hr) ) - return hr; + case TEX_FILTER_CUBIC: + if (filter & (TEX_FILTER_WRAP | TEX_FILTER_MIRROR)) + { + // WIC only supports 'clamp' semantics + return false; + } + + if (BitsPerColor(format) > 8) + { + // Avoid the WIC bitmap scaler when doing Cubic filtering of XR/HDR formats + return false; + } + break; + + case TEX_FILTER_TRIANGLE: + // WIC does not implement this filter + return false; } - } - return S_OK; -} - - -//--- Do conversion, resize using WIC, conversion cycle --- -static HRESULT _PerformResizeViaF32( _In_ const Image& srcImage, _In_ DWORD filter, _In_ const Image& destImage ) -{ - if ( !srcImage.pixels || !destImage.pixels ) - return E_POINTER; - - assert( srcImage.format != DXGI_FORMAT_R32G32B32A32_FLOAT ); - assert( srcImage.format == destImage.format ); - - ScratchImage temp; - HRESULT hr = _ConvertToR32G32B32A32( srcImage, temp ); - if ( FAILED(hr) ) - return hr; - - const Image *tsrc = temp.GetImage( 0, 0, 0 ); - if ( !tsrc ) - return E_POINTER; - - ScratchImage rtemp; - hr = rtemp.Initialize2D( DXGI_FORMAT_R32G32B32A32_FLOAT, destImage.width, destImage.height, 1, 1 ); - if ( FAILED(hr) ) - return hr; - - const Image *tdest = rtemp.GetImage( 0, 0, 0 ); - if ( !tdest ) - return E_POINTER; - - hr = _PerformResizeUsingWIC( *tsrc, filter, GUID_WICPixelFormat128bppRGBAFloat, *tdest ); - if ( FAILED(hr) ) - return hr; - - temp.Release(); - - hr = _ConvertFromR32G32B32A32( *tdest, destImage ); - if ( FAILED(hr) ) - return hr; - - return S_OK; -} - - -//--- determine when to use WIC vs. non-WIC paths --- -static bool _UseWICFiltering( _In_ DXGI_FORMAT format, _In_ DWORD filter ) -{ - if ( filter & TEX_FILTER_FORCE_NON_WIC ) - { - // Explicit flag indicates use of non-WIC code paths - return false; - } - - if ( filter & TEX_FILTER_FORCE_WIC ) - { - // Explicit flag to use WIC code paths, skips all the case checks below return true; } - if ( IsSRGB(format) || (filter & TEX_FILTER_SRGB) ) + + //------------------------------------------------------------------------------------- + // Resize custom filters + //------------------------------------------------------------------------------------- + + //--- Point Filter --- + HRESULT ResizePointFilter(const Image& srcImage, const Image& destImage) { - // Use non-WIC code paths for sRGB correct filtering - return false; - } + assert(srcImage.pixels && destImage.pixels); + assert(srcImage.format == destImage.format); -#if defined(_XBOX_ONE) && defined(_TITLE) - if ( format == DXGI_FORMAT_R16G16B16A16_FLOAT - || format == DXGI_FORMAT_R16_FLOAT ) - { - // Use non-WIC code paths as these conversions are not supported by Xbox One XDK - return false; - } -#endif + // Allocate temporary space (2 scanlines) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc( + (sizeof(XMVECTOR) * (srcImage.width + destImage.width)), 16))); + if (!scanline) + return E_OUTOFMEMORY; - static_assert( TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK" ); + XMVECTOR* target = scanline.get(); - switch ( filter & TEX_FILTER_MASK ) - { - case TEX_FILTER_LINEAR: - if ( filter & TEX_FILTER_WRAP ) - { - // WIC only supports 'clamp' semantics (MIRROR is equivalent to clamp for linear) - return false; - } - - if ( BitsPerColor(format) > 8 ) - { - // Avoid the WIC bitmap scaler when doing Linear filtering of XR/HDR formats - return false; - } - break; - - case TEX_FILTER_CUBIC: - if ( filter & ( TEX_FILTER_WRAP | TEX_FILTER_MIRROR ) ) - { - // WIC only supports 'clamp' semantics - return false; - } - - if ( BitsPerColor(format) > 8 ) - { - // Avoid the WIC bitmap scaler when doing Cubic filtering of XR/HDR formats - return false; - } - break; - - case TEX_FILTER_TRIANGLE: - // WIC does not implement this filter - return false; - } - - return true; -} - - -//------------------------------------------------------------------------------------- -// Resize custom filters -//------------------------------------------------------------------------------------- - -//--- Point Filter --- -static HRESULT _ResizePointFilter( _In_ const Image& srcImage, _In_ const Image& destImage ) -{ - assert( srcImage.pixels && destImage.pixels ); - assert( srcImage.format == destImage.format ); - - // Allocate temporary space (2 scanlines) - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( - ( sizeof(XMVECTOR) * (srcImage.width + destImage.width ) ), 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - XMVECTOR* target = scanline.get(); - - XMVECTOR* row = target + destImage.width; + XMVECTOR* row = target + destImage.width; #ifdef _DEBUG - memset( row, 0xCD, sizeof(XMVECTOR)*srcImage.width ); + memset(row, 0xCD, sizeof(XMVECTOR)*srcImage.width); #endif - const uint8_t* pSrc = srcImage.pixels; - uint8_t* pDest = destImage.pixels; + const uint8_t* pSrc = srcImage.pixels; + uint8_t* pDest = destImage.pixels; - size_t rowPitch = srcImage.rowPitch; + size_t rowPitch = srcImage.rowPitch; - size_t xinc = ( srcImage.width << 16 ) / destImage.width; - size_t yinc = ( srcImage.height << 16 ) / destImage.height; + size_t xinc = (srcImage.width << 16) / destImage.width; + size_t yinc = (srcImage.height << 16) / destImage.height; - size_t lasty = size_t(-1); + size_t lasty = size_t(-1); - size_t sy = 0; - for( size_t y = 0; y < destImage.height; ++y ) - { - if ( (lasty ^ sy) >> 16 ) + size_t sy = 0; + for (size_t y = 0; y < destImage.height; ++y) { - if ( !_LoadScanline( row, srcImage.width, pSrc + ( rowPitch * (sy >> 16) ), rowPitch, srcImage.format ) ) + if ((lasty ^ sy) >> 16) + { + if (!_LoadScanline(row, srcImage.width, pSrc + (rowPitch * (sy >> 16)), rowPitch, srcImage.format)) + return E_FAIL; + lasty = sy; + } + + size_t sx = 0; + for (size_t x = 0; x < destImage.width; ++x) + { + target[x] = row[sx >> 16]; + sx += xinc; + } + + if (!_StoreScanline(pDest, destImage.rowPitch, destImage.format, target, destImage.width)) return E_FAIL; - lasty = sy; + pDest += destImage.rowPitch; + + sy += yinc; } - size_t sx = 0; - for( size_t x = 0; x < destImage.width; ++x ) - { - target[ x ] = row[ sx >> 16 ]; - sx += xinc; - } - - if ( !_StoreScanline( pDest, destImage.rowPitch, destImage.format, target, destImage.width ) ) - return E_FAIL; - pDest += destImage.rowPitch; - - sy += yinc; + return S_OK; } - return S_OK; -} + //--- Box Filter --- + HRESULT ResizeBoxFilter(const Image& srcImage, DWORD filter, const Image& destImage) + { + assert(srcImage.pixels && destImage.pixels); + assert(srcImage.format == destImage.format); -//--- Box Filter --- -static HRESULT _ResizeBoxFilter( _In_ const Image& srcImage, _In_ DWORD filter, _In_ const Image& destImage ) -{ - assert( srcImage.pixels && destImage.pixels ); - assert( srcImage.format == destImage.format ); + if (((destImage.width << 1) != srcImage.width) || ((destImage.height << 1) != srcImage.height)) + return E_FAIL; - if ( ( (destImage.width << 1) != srcImage.width ) || ( (destImage.height << 1) != srcImage.height ) ) - return E_FAIL; + // Allocate temporary space (3 scanlines) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc( + (sizeof(XMVECTOR) * (srcImage.width * 2 + destImage.width)), 16))); + if (!scanline) + return E_OUTOFMEMORY; - // Allocate temporary space (3 scanlines) - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( - ( sizeof(XMVECTOR) * ( srcImage.width*2 + destImage.width ) ), 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; + XMVECTOR* target = scanline.get(); - XMVECTOR* target = scanline.get(); - - XMVECTOR* urow0 = target + destImage.width; - XMVECTOR* urow1 = urow0 + srcImage.width; + XMVECTOR* urow0 = target + destImage.width; + XMVECTOR* urow1 = urow0 + srcImage.width; #ifdef _DEBUG - memset( urow0, 0xCD, sizeof(XMVECTOR)*srcImage.width ); - memset( urow1, 0xDD, sizeof(XMVECTOR)*srcImage.width ); + memset(urow0, 0xCD, sizeof(XMVECTOR)*srcImage.width); + memset(urow1, 0xDD, sizeof(XMVECTOR)*srcImage.width); #endif - const XMVECTOR* urow2 = urow0 + 1; - const XMVECTOR* urow3 = urow1 + 1; + const XMVECTOR* urow2 = urow0 + 1; + const XMVECTOR* urow3 = urow1 + 1; - const uint8_t* pSrc = srcImage.pixels; - uint8_t* pDest = destImage.pixels; + const uint8_t* pSrc = srcImage.pixels; + uint8_t* pDest = destImage.pixels; - size_t rowPitch = srcImage.rowPitch; + size_t rowPitch = srcImage.rowPitch; - for( size_t y = 0; y < destImage.height; ++y ) - { - if ( !_LoadScanlineLinear( urow0, srcImage.width, pSrc, rowPitch, srcImage.format, filter ) ) - return E_FAIL; - pSrc += rowPitch; - - if ( urow0 != urow1 ) + for (size_t y = 0; y < destImage.height; ++y) { - if ( !_LoadScanlineLinear( urow1, srcImage.width, pSrc, rowPitch, srcImage.format, filter ) ) + if (!_LoadScanlineLinear(urow0, srcImage.width, pSrc, rowPitch, srcImage.format, filter)) return E_FAIL; pSrc += rowPitch; - } - for( size_t x = 0; x < destImage.width; ++x ) - { - size_t x2 = x << 1; - - AVERAGE4( target[ x ], urow0[ x2 ], urow1[ x2 ], urow2[ x2 ], urow3[ x2 ] ); - } - - if ( !_StoreScanlineLinear( pDest, destImage.rowPitch, destImage.format, target, destImage.width, filter ) ) - return E_FAIL; - pDest += destImage.rowPitch; - } - - return S_OK; -} - - -//--- Linear Filter --- -static HRESULT _ResizeLinearFilter( _In_ const Image& srcImage, _In_ DWORD filter, _In_ const Image& destImage ) -{ - assert( srcImage.pixels && destImage.pixels ); - assert( srcImage.format == destImage.format ); - - // Allocate temporary space (3 scanlines, plus X and Y filters) - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( - ( sizeof(XMVECTOR) * ( srcImage.width*2 + destImage.width ) ), 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - std::unique_ptr lf( new (std::nothrow) LinearFilter[ destImage.width + destImage.height ] ); - if ( !lf ) - return E_OUTOFMEMORY; - - LinearFilter* lfX = lf.get(); - LinearFilter* lfY = lf.get() + destImage.width; - - _CreateLinearFilter( srcImage.width, destImage.width, (filter & TEX_FILTER_WRAP_U) != 0, lfX ); - _CreateLinearFilter( srcImage.height, destImage.height, (filter & TEX_FILTER_WRAP_V) != 0, lfY ); - - XMVECTOR* target = scanline.get(); - - XMVECTOR* row0 = target + destImage.width; - XMVECTOR* row1 = row0 + srcImage.width; - -#ifdef _DEBUG - memset( row0, 0xCD, sizeof(XMVECTOR)*srcImage.width ); - memset( row1, 0xDD, sizeof(XMVECTOR)*srcImage.width ); -#endif - - const uint8_t* pSrc = srcImage.pixels; - uint8_t* pDest = destImage.pixels; - - size_t rowPitch = srcImage.rowPitch; - - size_t u0 = size_t(-1); - size_t u1 = size_t(-1); - - for( size_t y = 0; y < destImage.height; ++y ) - { - auto& toY = lfY[ y ]; - - if ( toY.u0 != u0 ) - { - if ( toY.u0 != u1 ) + if (urow0 != urow1) { - u0 = toY.u0; - - if ( !_LoadScanlineLinear( row0, srcImage.width, pSrc + (rowPitch * u0), rowPitch, srcImage.format, filter ) ) + if (!_LoadScanlineLinear(urow1, srcImage.width, pSrc, rowPitch, srcImage.format, filter)) return E_FAIL; + pSrc += rowPitch; } - else + + for (size_t x = 0; x < destImage.width; ++x) { - u0 = u1; - u1 = size_t(-1); + size_t x2 = x << 1; - std::swap( row0, row1 ); + AVERAGE4(target[x], urow0[x2], urow1[x2], urow2[x2], urow3[x2]); } - } - if ( toY.u1 != u1 ) - { - u1 = toY.u1; - - if ( !_LoadScanlineLinear( row1, srcImage.width, pSrc + (rowPitch * u1), rowPitch, srcImage.format, filter ) ) + if (!_StoreScanlineLinear(pDest, destImage.rowPitch, destImage.format, target, destImage.width, filter)) return E_FAIL; + pDest += destImage.rowPitch; } - for( size_t x = 0; x < destImage.width; ++x ) - { - auto& toX = lfX[ x ]; - - BILINEAR_INTERPOLATE( target[x], toX, toY, row0, row1 ); - } - - if ( !_StoreScanlineLinear( pDest, destImage.rowPitch, destImage.format, target, destImage.width, filter ) ) - return E_FAIL; - pDest += destImage.rowPitch; + return S_OK; } - return S_OK; -} + //--- Linear Filter --- + HRESULT ResizeLinearFilter(const Image& srcImage, DWORD filter, const Image& destImage) + { + assert(srcImage.pixels && destImage.pixels); + assert(srcImage.format == destImage.format); -//--- Cubic Filter --- -static HRESULT _ResizeCubicFilter( _In_ const Image& srcImage, _In_ DWORD filter, _In_ const Image& destImage ) -{ - assert( srcImage.pixels && destImage.pixels ); - assert( srcImage.format == destImage.format ); + // Allocate temporary space (3 scanlines, plus X and Y filters) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc( + (sizeof(XMVECTOR) * (srcImage.width * 2 + destImage.width)), 16))); + if (!scanline) + return E_OUTOFMEMORY; - // Allocate temporary space (5 scanlines, plus X and Y filters) - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( - ( sizeof(XMVECTOR) * ( srcImage.width*4 + destImage.width ) ), 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; + std::unique_ptr lf(new (std::nothrow) LinearFilter[destImage.width + destImage.height]); + if (!lf) + return E_OUTOFMEMORY; - std::unique_ptr cf( new (std::nothrow) CubicFilter[ destImage.width + destImage.height ] ); - if ( !cf ) - return E_OUTOFMEMORY; + LinearFilter* lfX = lf.get(); + LinearFilter* lfY = lf.get() + destImage.width; - CubicFilter* cfX = cf.get(); - CubicFilter* cfY = cf.get() + destImage.width; + _CreateLinearFilter(srcImage.width, destImage.width, (filter & TEX_FILTER_WRAP_U) != 0, lfX); + _CreateLinearFilter(srcImage.height, destImage.height, (filter & TEX_FILTER_WRAP_V) != 0, lfY); - _CreateCubicFilter( srcImage.width, destImage.width, (filter & TEX_FILTER_WRAP_U) != 0, (filter & TEX_FILTER_MIRROR_U) != 0, cfX ); - _CreateCubicFilter( srcImage.height, destImage.height, (filter & TEX_FILTER_WRAP_V) != 0, (filter & TEX_FILTER_MIRROR_V) != 0, cfY ); + XMVECTOR* target = scanline.get(); - XMVECTOR* target = scanline.get(); - - XMVECTOR* row0 = target + destImage.width; - XMVECTOR* row1 = row0 + srcImage.width; - XMVECTOR* row2 = row0 + srcImage.width*2; - XMVECTOR* row3 = row0 + srcImage.width*3; + XMVECTOR* row0 = target + destImage.width; + XMVECTOR* row1 = row0 + srcImage.width; #ifdef _DEBUG - memset( row0, 0xCD, sizeof(XMVECTOR)*srcImage.width ); - memset( row1, 0xDD, sizeof(XMVECTOR)*srcImage.width ); - memset( row2, 0xED, sizeof(XMVECTOR)*srcImage.width ); - memset( row3, 0xFD, sizeof(XMVECTOR)*srcImage.width ); + memset(row0, 0xCD, sizeof(XMVECTOR)*srcImage.width); + memset(row1, 0xDD, sizeof(XMVECTOR)*srcImage.width); #endif - const uint8_t* pSrc = srcImage.pixels; - uint8_t* pDest = destImage.pixels; + const uint8_t* pSrc = srcImage.pixels; + uint8_t* pDest = destImage.pixels; - size_t rowPitch = srcImage.rowPitch; + size_t rowPitch = srcImage.rowPitch; - size_t u0 = size_t(-1); - size_t u1 = size_t(-1); - size_t u2 = size_t(-1); - size_t u3 = size_t(-1); + size_t u0 = size_t(-1); + size_t u1 = size_t(-1); - for( size_t y = 0; y < destImage.height; ++y ) - { - auto& toY = cfY[ y ]; - - // Scanline 1 - if ( toY.u0 != u0 ) + for (size_t y = 0; y < destImage.height; ++y) { - if ( toY.u0 != u1 && toY.u0 != u2 && toY.u0 != u3 ) + auto& toY = lfY[y]; + + if (toY.u0 != u0) { - u0 = toY.u0; - - if ( !_LoadScanlineLinear( row0, srcImage.width, pSrc + (rowPitch * u0), rowPitch, srcImage.format, filter ) ) - return E_FAIL; - } - else if ( toY.u0 == u1 ) - { - u0 = u1; - u1 = size_t(-1); - - std::swap( row0, row1 ); - } - else if ( toY.u0 == u2 ) - { - u0 = u2; - u2 = size_t(-1); - - std::swap( row0, row2 ); - } - else if ( toY.u0 == u3 ) - { - u0 = u3; - u3 = size_t(-1); - - std::swap( row0, row3 ); - } - } - - // Scanline 2 - if ( toY.u1 != u1 ) - { - if ( toY.u1 != u2 && toY.u1 != u3 ) - { - u1 = toY.u1; - - if ( !_LoadScanlineLinear( row1, srcImage.width, pSrc + (rowPitch * u1), rowPitch, srcImage.format, filter ) ) - return E_FAIL; - } - else if ( toY.u1 == u2 ) - { - u1 = u2; - u2 = size_t(-1); - - std::swap( row1, row2 ); - } - else if ( toY.u1 == u3 ) - { - u1 = u3; - u3 = size_t(-1); - - std::swap( row1, row3 ); - } - } - - // Scanline 3 - if ( toY.u2 != u2 ) - { - if ( toY.u2 != u3 ) - { - u2 = toY.u2; - - if ( !_LoadScanlineLinear( row2, srcImage.width, pSrc + (rowPitch * u2), rowPitch, srcImage.format, filter ) ) - return E_FAIL; - } - else - { - u2 = u3; - u3 = size_t(-1); - - std::swap( row2, row3 ); - } - } - - // Scanline 4 - if ( toY.u3 != u3 ) - { - u3 = toY.u3; - - if ( !_LoadScanlineLinear( row3, srcImage.width, pSrc + (rowPitch * u3), rowPitch, srcImage.format, filter ) ) - return E_FAIL; - } - - for( size_t x = 0; x < destImage.width; ++x ) - { - auto& toX = cfX[ x ]; - - XMVECTOR C0, C1, C2, C3; - - CUBIC_INTERPOLATE( C0, toX.x, row0[ toX.u0 ], row0[ toX.u1 ], row0[ toX.u2 ], row0[ toX.u3 ] ); - CUBIC_INTERPOLATE( C1, toX.x, row1[ toX.u0 ], row1[ toX.u1 ], row1[ toX.u2 ], row1[ toX.u3 ] ); - CUBIC_INTERPOLATE( C2, toX.x, row2[ toX.u0 ], row2[ toX.u1 ], row2[ toX.u2 ], row2[ toX.u3 ] ); - CUBIC_INTERPOLATE( C3, toX.x, row3[ toX.u0 ], row3[ toX.u1 ], row3[ toX.u2 ], row3[ toX.u3 ] ); - - CUBIC_INTERPOLATE( target[x], toY.x, C0, C1, C2, C3 ); - } - - if ( !_StoreScanlineLinear( pDest, destImage.rowPitch, destImage.format, target, destImage.width, filter ) ) - return E_FAIL; - pDest += destImage.rowPitch; - } - - return S_OK; -} - - -//--- Triangle Filter --- -static HRESULT _ResizeTriangleFilter( _In_ const Image& srcImage, _In_ DWORD filter, _In_ const Image& destImage ) -{ - assert( srcImage.pixels && destImage.pixels ); - assert( srcImage.format == destImage.format ); - - using namespace TriangleFilter; - - // Allocate initial temporary space (1 scanline, accumulation rows, plus X and Y filters) - ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast( _aligned_malloc( sizeof(XMVECTOR) * srcImage.width, 16 ) ) ); - if ( !scanline ) - return E_OUTOFMEMORY; - - std::unique_ptr rowActive( new (std::nothrow) TriangleRow[ destImage.height ] ); - if ( !rowActive ) - return E_OUTOFMEMORY; - - TriangleRow * rowFree = nullptr; - - std::unique_ptr tfX; - HRESULT hr = _Create( srcImage.width, destImage.width, (filter & TEX_FILTER_WRAP_U) != 0, tfX ); - if ( FAILED(hr) ) - return hr; - - std::unique_ptr tfY; - hr = _Create( srcImage.height, destImage.height, (filter & TEX_FILTER_WRAP_V) != 0, tfY ); - if ( FAILED(hr) ) - return hr; - - XMVECTOR* row = scanline.get(); - -#ifdef _DEBUG - memset( row, 0xCD, sizeof(XMVECTOR)*srcImage.width ); -#endif - - auto xFromEnd = reinterpret_cast( reinterpret_cast( tfX.get() ) + tfX->sizeInBytes ); - auto yFromEnd = reinterpret_cast( reinterpret_cast( tfY.get() ) + tfY->sizeInBytes ); - - // Count times rows get written - for( FilterFrom* yFrom = tfY->from; yFrom < yFromEnd; ) - { - for ( size_t j = 0; j < yFrom->count; ++j ) - { - size_t v = yFrom->to[ j ].u; - assert( v < destImage.height ); - ++rowActive[ v ].remaining; - } - - yFrom = reinterpret_cast( reinterpret_cast( yFrom ) + yFrom->sizeInBytes ); - } - - // Filter image - const uint8_t* pSrc = srcImage.pixels; - size_t rowPitch = srcImage.rowPitch; - const uint8_t* pEndSrc = pSrc + rowPitch * srcImage.height; - - uint8_t* pDest = destImage.pixels; - - for( FilterFrom* yFrom = tfY->from; yFrom < yFromEnd; ) - { - // Create accumulation rows as needed - for ( size_t j = 0; j < yFrom->count; ++j ) - { - size_t v = yFrom->to[ j ].u; - assert( v < destImage.height ); - TriangleRow* rowAcc = &rowActive[ v ]; - - if ( !rowAcc->scanline ) - { - if ( rowFree ) + if (toY.u0 != u1) { - // Steal and reuse scanline from 'free row' list - assert( rowFree->scanline != 0 ); - rowAcc->scanline.reset( rowFree->scanline.release() ); - rowFree = rowFree->next; + u0 = toY.u0; + + if (!_LoadScanlineLinear(row0, srcImage.width, pSrc + (rowPitch * u0), rowPitch, srcImage.format, filter)) + return E_FAIL; } else { - rowAcc->scanline.reset( reinterpret_cast( _aligned_malloc( sizeof(XMVECTOR) * destImage.width, 16 ) ) ); - if ( !rowAcc->scanline ) - return E_OUTOFMEMORY; - } + u0 = u1; + u1 = size_t(-1); - memset( rowAcc->scanline.get(), 0, sizeof(XMVECTOR) * destImage.width ); - } - } - - // Load source scanline - if ( (pSrc + rowPitch) > pEndSrc ) - return E_FAIL; - - if ( !_LoadScanlineLinear( row, srcImage.width, pSrc, rowPitch, srcImage.format, filter ) ) - return E_FAIL; - - pSrc += rowPitch; - - // Process row - size_t x = 0; - for( FilterFrom* xFrom = tfX->from; xFrom < xFromEnd; ++x ) - { - for ( size_t j = 0; j < yFrom->count; ++j ) - { - size_t v = yFrom->to[ j ].u; - assert( v < destImage.height ); - float yweight = yFrom->to[ j ].weight; - - XMVECTOR* accPtr = rowActive[ v ].scanline.get(); - if ( !accPtr ) - return E_POINTER; - - for ( size_t k = 0; k < xFrom->count; ++k ) - { - size_t u = xFrom->to[ k ].u; - assert( u < destImage.width ); - - XMVECTOR weight = XMVectorReplicate( yweight * xFrom->to[ k ].weight ); - - assert( x < srcImage.width ); - accPtr[ u ] = XMVectorMultiplyAdd( row[ x ], weight, accPtr[ u ] ); + std::swap(row0, row1); } } - xFrom = reinterpret_cast( reinterpret_cast( xFrom ) + xFrom->sizeInBytes ); + if (toY.u1 != u1) + { + u1 = toY.u1; + + if (!_LoadScanlineLinear(row1, srcImage.width, pSrc + (rowPitch * u1), rowPitch, srcImage.format, filter)) + return E_FAIL; + } + + for (size_t x = 0; x < destImage.width; ++x) + { + auto& toX = lfX[x]; + + BILINEAR_INTERPOLATE(target[x], toX, toY, row0, row1); + } + + if (!_StoreScanlineLinear(pDest, destImage.rowPitch, destImage.format, target, destImage.width, filter)) + return E_FAIL; + pDest += destImage.rowPitch; } - // Write completed accumulation rows - for ( size_t j = 0; j < yFrom->count; ++j ) + return S_OK; + } + + + //--- Cubic Filter --- + HRESULT ResizeCubicFilter(const Image& srcImage, DWORD filter, const Image& destImage) + { + assert(srcImage.pixels && destImage.pixels); + assert(srcImage.format == destImage.format); + + // Allocate temporary space (5 scanlines, plus X and Y filters) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc( + (sizeof(XMVECTOR) * (srcImage.width * 4 + destImage.width)), 16))); + if (!scanline) + return E_OUTOFMEMORY; + + std::unique_ptr cf(new (std::nothrow) CubicFilter[destImage.width + destImage.height]); + if (!cf) + return E_OUTOFMEMORY; + + CubicFilter* cfX = cf.get(); + CubicFilter* cfY = cf.get() + destImage.width; + + _CreateCubicFilter(srcImage.width, destImage.width, (filter & TEX_FILTER_WRAP_U) != 0, (filter & TEX_FILTER_MIRROR_U) != 0, cfX); + _CreateCubicFilter(srcImage.height, destImage.height, (filter & TEX_FILTER_WRAP_V) != 0, (filter & TEX_FILTER_MIRROR_V) != 0, cfY); + + XMVECTOR* target = scanline.get(); + + XMVECTOR* row0 = target + destImage.width; + XMVECTOR* row1 = row0 + srcImage.width; + XMVECTOR* row2 = row0 + srcImage.width * 2; + XMVECTOR* row3 = row0 + srcImage.width * 3; + +#ifdef _DEBUG + memset(row0, 0xCD, sizeof(XMVECTOR)*srcImage.width); + memset(row1, 0xDD, sizeof(XMVECTOR)*srcImage.width); + memset(row2, 0xED, sizeof(XMVECTOR)*srcImage.width); + memset(row3, 0xFD, sizeof(XMVECTOR)*srcImage.width); +#endif + + const uint8_t* pSrc = srcImage.pixels; + uint8_t* pDest = destImage.pixels; + + size_t rowPitch = srcImage.rowPitch; + + size_t u0 = size_t(-1); + size_t u1 = size_t(-1); + size_t u2 = size_t(-1); + size_t u3 = size_t(-1); + + for (size_t y = 0; y < destImage.height; ++y) { - size_t v = yFrom->to[ j ].u; - assert( v < destImage.height ); - TriangleRow* rowAcc = &rowActive[ v ]; + auto& toY = cfY[y]; - assert( rowAcc->remaining > 0 ); - --rowAcc->remaining; - - if ( !rowAcc->remaining ) + // Scanline 1 + if (toY.u0 != u0) { - XMVECTOR* pAccSrc = rowAcc->scanline.get(); - if ( !pAccSrc ) - return E_POINTER; - - switch( destImage.format ) + if (toY.u0 != u1 && toY.u0 != u2 && toY.u0 != u3) { - case DXGI_FORMAT_R10G10B10A2_UNORM: - case DXGI_FORMAT_R10G10B10A2_UINT: + u0 = toY.u0; + + if (!_LoadScanlineLinear(row0, srcImage.width, pSrc + (rowPitch * u0), rowPitch, srcImage.format, filter)) + return E_FAIL; + } + else if (toY.u0 == u1) + { + u0 = u1; + u1 = size_t(-1); + + std::swap(row0, row1); + } + else if (toY.u0 == u2) + { + u0 = u2; + u2 = size_t(-1); + + std::swap(row0, row2); + } + else if (toY.u0 == u3) + { + u0 = u3; + u3 = size_t(-1); + + std::swap(row0, row3); + } + } + + // Scanline 2 + if (toY.u1 != u1) + { + if (toY.u1 != u2 && toY.u1 != u3) + { + u1 = toY.u1; + + if (!_LoadScanlineLinear(row1, srcImage.width, pSrc + (rowPitch * u1), rowPitch, srcImage.format, filter)) + return E_FAIL; + } + else if (toY.u1 == u2) + { + u1 = u2; + u2 = size_t(-1); + + std::swap(row1, row2); + } + else if (toY.u1 == u3) + { + u1 = u3; + u3 = size_t(-1); + + std::swap(row1, row3); + } + } + + // Scanline 3 + if (toY.u2 != u2) + { + if (toY.u2 != u3) + { + u2 = toY.u2; + + if (!_LoadScanlineLinear(row2, srcImage.width, pSrc + (rowPitch * u2), rowPitch, srcImage.format, filter)) + return E_FAIL; + } + else + { + u2 = u3; + u3 = size_t(-1); + + std::swap(row2, row3); + } + } + + // Scanline 4 + if (toY.u3 != u3) + { + u3 = toY.u3; + + if (!_LoadScanlineLinear(row3, srcImage.width, pSrc + (rowPitch * u3), rowPitch, srcImage.format, filter)) + return E_FAIL; + } + + for (size_t x = 0; x < destImage.width; ++x) + { + auto& toX = cfX[x]; + + XMVECTOR C0, C1, C2, C3; + + CUBIC_INTERPOLATE(C0, toX.x, row0[toX.u0], row0[toX.u1], row0[toX.u2], row0[toX.u3]); + CUBIC_INTERPOLATE(C1, toX.x, row1[toX.u0], row1[toX.u1], row1[toX.u2], row1[toX.u3]); + CUBIC_INTERPOLATE(C2, toX.x, row2[toX.u0], row2[toX.u1], row2[toX.u2], row2[toX.u3]); + CUBIC_INTERPOLATE(C3, toX.x, row3[toX.u0], row3[toX.u1], row3[toX.u2], row3[toX.u3]); + + CUBIC_INTERPOLATE(target[x], toY.x, C0, C1, C2, C3); + } + + if (!_StoreScanlineLinear(pDest, destImage.rowPitch, destImage.format, target, destImage.width, filter)) + return E_FAIL; + pDest += destImage.rowPitch; + } + + return S_OK; + } + + + //--- Triangle Filter --- + HRESULT ResizeTriangleFilter(const Image& srcImage, DWORD filter, const Image& destImage) + { + assert(srcImage.pixels && destImage.pixels); + assert(srcImage.format == destImage.format); + + using namespace TriangleFilter; + + // Allocate initial temporary space (1 scanline, accumulation rows, plus X and Y filters) + ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast(_aligned_malloc(sizeof(XMVECTOR) * srcImage.width, 16))); + if (!scanline) + return E_OUTOFMEMORY; + + std::unique_ptr rowActive(new (std::nothrow) TriangleRow[destImage.height]); + if (!rowActive) + return E_OUTOFMEMORY; + + TriangleRow * rowFree = nullptr; + + std::unique_ptr tfX; + HRESULT hr = _Create(srcImage.width, destImage.width, (filter & TEX_FILTER_WRAP_U) != 0, tfX); + if (FAILED(hr)) + return hr; + + std::unique_ptr tfY; + hr = _Create(srcImage.height, destImage.height, (filter & TEX_FILTER_WRAP_V) != 0, tfY); + if (FAILED(hr)) + return hr; + + XMVECTOR* row = scanline.get(); + +#ifdef _DEBUG + memset(row, 0xCD, sizeof(XMVECTOR)*srcImage.width); +#endif + + auto xFromEnd = reinterpret_cast(reinterpret_cast(tfX.get()) + tfX->sizeInBytes); + auto yFromEnd = reinterpret_cast(reinterpret_cast(tfY.get()) + tfY->sizeInBytes); + + // Count times rows get written + for (FilterFrom* yFrom = tfY->from; yFrom < yFromEnd; ) + { + for (size_t j = 0; j < yFrom->count; ++j) + { + size_t v = yFrom->to[j].u; + assert(v < destImage.height); + ++rowActive[v].remaining; + } + + yFrom = reinterpret_cast(reinterpret_cast(yFrom) + yFrom->sizeInBytes); + } + + // Filter image + const uint8_t* pSrc = srcImage.pixels; + size_t rowPitch = srcImage.rowPitch; + const uint8_t* pEndSrc = pSrc + rowPitch * srcImage.height; + + uint8_t* pDest = destImage.pixels; + + for (FilterFrom* yFrom = tfY->from; yFrom < yFromEnd; ) + { + // Create accumulation rows as needed + for (size_t j = 0; j < yFrom->count; ++j) + { + size_t v = yFrom->to[j].u; + assert(v < destImage.height); + TriangleRow* rowAcc = &rowActive[v]; + + if (!rowAcc->scanline) + { + if (rowFree) + { + // Steal and reuse scanline from 'free row' list + assert(rowFree->scanline != 0); + rowAcc->scanline.reset(rowFree->scanline.release()); + rowFree = rowFree->next; + } + else + { + rowAcc->scanline.reset(reinterpret_cast(_aligned_malloc(sizeof(XMVECTOR) * destImage.width, 16))); + if (!rowAcc->scanline) + return E_OUTOFMEMORY; + } + + memset(rowAcc->scanline.get(), 0, sizeof(XMVECTOR) * destImage.width); + } + } + + // Load source scanline + if ((pSrc + rowPitch) > pEndSrc) + return E_FAIL; + + if (!_LoadScanlineLinear(row, srcImage.width, pSrc, rowPitch, srcImage.format, filter)) + return E_FAIL; + + pSrc += rowPitch; + + // Process row + size_t x = 0; + for (FilterFrom* xFrom = tfX->from; xFrom < xFromEnd; ++x) + { + for (size_t j = 0; j < yFrom->count; ++j) + { + size_t v = yFrom->to[j].u; + assert(v < destImage.height); + float yweight = yFrom->to[j].weight; + + XMVECTOR* accPtr = rowActive[v].scanline.get(); + if (!accPtr) + return E_POINTER; + + for (size_t k = 0; k < xFrom->count; ++k) + { + size_t u = xFrom->to[k].u; + assert(u < destImage.width); + + XMVECTOR weight = XMVectorReplicate(yweight * xFrom->to[k].weight); + + assert(x < srcImage.width); + accPtr[u] = XMVectorMultiplyAdd(row[x], weight, accPtr[u]); + } + } + + xFrom = reinterpret_cast(reinterpret_cast(xFrom) + xFrom->sizeInBytes); + } + + // Write completed accumulation rows + for (size_t j = 0; j < yFrom->count; ++j) + { + size_t v = yFrom->to[j].u; + assert(v < destImage.height); + TriangleRow* rowAcc = &rowActive[v]; + + assert(rowAcc->remaining > 0); + --rowAcc->remaining; + + if (!rowAcc->remaining) + { + XMVECTOR* pAccSrc = rowAcc->scanline.get(); + if (!pAccSrc) + return E_POINTER; + + switch (destImage.format) + { + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: { // Need to slightly bias results for floating-point error accumulation which can // be visible with harshly quantized values static const XMVECTORF32 Bias = { 0.f, 0.f, 0.f, 0.1f }; - + XMVECTOR* ptr = pAccSrc; - for( size_t i=0; i < destImage.width; ++i, ++ptr ) + for (size_t i = 0; i < destImage.width; ++i, ++ptr) { - *ptr = XMVectorAdd( *ptr, Bias ); + *ptr = XMVectorAdd(*ptr, Bias); } } break; + } + + // This performs any required clamping + if (!_StoreScanlineLinear(pDest + (destImage.rowPitch * v), destImage.rowPitch, destImage.format, pAccSrc, destImage.width, filter)) + return E_FAIL; + + // Put row on freelist to reuse it's allocated scanline + rowAcc->next = rowFree; + rowFree = rowAcc; } - - // This performs any required clamping - if ( !_StoreScanlineLinear( pDest + (destImage.rowPitch * v), destImage.rowPitch, destImage.format, pAccSrc, destImage.width, filter ) ) - return E_FAIL; - - // Put row on freelist to reuse it's allocated scanline - rowAcc->next = rowFree; - rowFree = rowAcc; } + + yFrom = reinterpret_cast(reinterpret_cast(yFrom) + yFrom->sizeInBytes); } - yFrom = reinterpret_cast( reinterpret_cast( yFrom ) + yFrom->sizeInBytes ); + return S_OK; } - return S_OK; -} - -//--- Custom filter resize --- -static HRESULT _PerformResizeUsingCustomFilters( _In_ const Image& srcImage, _In_ DWORD filter, _In_ const Image& destImage ) -{ - if ( !srcImage.pixels || !destImage.pixels ) - return E_POINTER; - - static_assert( TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK" ); - - DWORD filter_select = ( filter & TEX_FILTER_MASK ); - if ( !filter_select ) + //--- Custom filter resize --- + HRESULT PerformResizeUsingCustomFilters(const Image& srcImage, DWORD filter, const Image& destImage) { - // Default filter choice - filter_select = ( ( (destImage.width << 1) == srcImage.width ) && ( (destImage.height << 1) == srcImage.height ) ) - ? TEX_FILTER_BOX : TEX_FILTER_LINEAR; - } + if (!srcImage.pixels || !destImage.pixels) + return E_POINTER; - switch( filter_select ) - { - case TEX_FILTER_POINT: - return _ResizePointFilter( srcImage, destImage ); - - case TEX_FILTER_BOX: - return _ResizeBoxFilter( srcImage, filter, destImage ); + static_assert(TEX_FILTER_POINT == 0x100000, "TEX_FILTER_ flag values don't match TEX_FILTER_MASK"); - case TEX_FILTER_LINEAR: - return _ResizeLinearFilter( srcImage, filter, destImage ); + DWORD filter_select = (filter & TEX_FILTER_MASK); + if (!filter_select) + { + // Default filter choice + filter_select = (((destImage.width << 1) == srcImage.width) && ((destImage.height << 1) == srcImage.height)) + ? TEX_FILTER_BOX : TEX_FILTER_LINEAR; + } - case TEX_FILTER_CUBIC: - return _ResizeCubicFilter( srcImage, filter, destImage ); + switch (filter_select) + { + case TEX_FILTER_POINT: + return ResizePointFilter(srcImage, destImage); - case TEX_FILTER_TRIANGLE: - return _ResizeTriangleFilter( srcImage, filter, destImage ); + case TEX_FILTER_BOX: + return ResizeBoxFilter(srcImage, filter, destImage); - default: - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + case TEX_FILTER_LINEAR: + return ResizeLinearFilter(srcImage, filter, destImage); + + case TEX_FILTER_CUBIC: + return ResizeCubicFilter(srcImage, filter, destImage); + + case TEX_FILTER_TRIANGLE: + return ResizeTriangleFilter(srcImage, filter, destImage); + + default: + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } } } @@ -828,54 +834,59 @@ static HRESULT _PerformResizeUsingCustomFilters( _In_ const Image& srcImage, _In // Resize image //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT Resize( const Image& srcImage, size_t width, size_t height, DWORD filter, ScratchImage& image ) +HRESULT DirectX::Resize( + const Image& srcImage, + size_t width, + size_t height, + DWORD filter, + ScratchImage& image) { - if ( width == 0 || height == 0 ) + if (width == 0 || height == 0) return E_INVALIDARG; - if ( (srcImage.width > UINT32_MAX) || (srcImage.height > UINT32_MAX) ) + if ((srcImage.width > UINT32_MAX) || (srcImage.height > UINT32_MAX)) return E_INVALIDARG; - if ( (width > UINT32_MAX) || (height > UINT32_MAX) ) + if ((width > UINT32_MAX) || (height > UINT32_MAX)) return E_INVALIDARG; - if ( !srcImage.pixels ) + if (!srcImage.pixels) return E_POINTER; - if ( IsCompressed( srcImage.format ) ) + if (IsCompressed(srcImage.format)) { // We don't support resizing compressed images - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } - HRESULT hr = image.Initialize2D( srcImage.format, width, height, 1, 1 ); - if ( FAILED(hr) ) + HRESULT hr = image.Initialize2D(srcImage.format, width, height, 1, 1); + if (FAILED(hr)) return hr; - - const Image *rimage = image.GetImage( 0, 0, 0 ); - if ( !rimage ) + + const Image *rimage = image.GetImage(0, 0, 0); + if (!rimage) return E_POINTER; - if ( _UseWICFiltering( srcImage.format, filter ) ) + if (UseWICFiltering(srcImage.format, filter)) { WICPixelFormatGUID pfGUID; - if ( _DXGIToWIC( srcImage.format, pfGUID, true ) ) + if (_DXGIToWIC(srcImage.format, pfGUID, true)) { // Case 1: Source format is supported by Windows Imaging Component - hr = _PerformResizeUsingWIC( srcImage, filter, pfGUID, *rimage ); + hr = PerformResizeUsingWIC(srcImage, filter, pfGUID, *rimage); } else { // Case 2: Source format is not supported by WIC, so we have to convert, resize, and convert back - hr = _PerformResizeViaF32( srcImage, filter, *rimage ); + hr = PerformResizeViaF32(srcImage, filter, *rimage); } } else { - hr = _PerformResizeUsingCustomFilters( srcImage, filter, *rimage ); + hr = PerformResizeUsingCustomFilters(srcImage, filter, *rimage); } - if ( FAILED(hr) ) + if (FAILED(hr)) { image.Release(); return hr; @@ -889,83 +900,89 @@ HRESULT Resize( const Image& srcImage, size_t width, size_t height, DWORD filter // Resize image (complex) //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT Resize( const Image* srcImages, size_t nimages, const TexMetadata& metadata, - size_t width, size_t height, DWORD filter, ScratchImage& result ) +HRESULT DirectX::Resize( + const Image* srcImages, + size_t nimages, + const TexMetadata& metadata, + size_t width, + size_t height, + DWORD filter, + ScratchImage& result) { - if ( !srcImages || !nimages || width == 0 || height == 0 ) + if (!srcImages || !nimages || width == 0 || height == 0) return E_INVALIDARG; - if ( (width > UINT32_MAX) || (height > UINT32_MAX) ) + if ((width > UINT32_MAX) || (height > UINT32_MAX)) return E_INVALIDARG; TexMetadata mdata2 = metadata; mdata2.width = width; mdata2.height = height; mdata2.mipLevels = 1; - HRESULT hr = result.Initialize( mdata2 ); - if ( FAILED(hr) ) + HRESULT hr = result.Initialize(mdata2); + if (FAILED(hr)) return hr; - bool usewic = _UseWICFiltering( metadata.format, filter ); + bool usewic = UseWICFiltering(metadata.format, filter); - WICPixelFormatGUID pfGUID = {0}; - bool wicpf = ( usewic ) ? _DXGIToWIC( metadata.format, pfGUID, true ) : false; + WICPixelFormatGUID pfGUID = { 0 }; + bool wicpf = (usewic) ? _DXGIToWIC(metadata.format, pfGUID, true) : false; - switch ( metadata.dimension ) + switch (metadata.dimension) { case TEX_DIMENSION_TEXTURE1D: case TEX_DIMENSION_TEXTURE2D: - assert( metadata.depth == 1 ); + assert(metadata.depth == 1); - for( size_t item = 0; item < metadata.arraySize; ++item ) + for (size_t item = 0; item < metadata.arraySize; ++item) { - size_t srcIndex = metadata.ComputeIndex( 0, item, 0 ); - if ( srcIndex >= nimages ) + size_t srcIndex = metadata.ComputeIndex(0, item, 0); + if (srcIndex >= nimages) { result.Release(); return E_FAIL; } - const Image* srcimg = &srcImages[ srcIndex ]; - const Image* destimg = result.GetImage( 0, item, 0 ); - if ( !srcimg || !destimg ) + const Image* srcimg = &srcImages[srcIndex]; + const Image* destimg = result.GetImage(0, item, 0); + if (!srcimg || !destimg) { result.Release(); return E_POINTER; } - if ( srcimg->format != metadata.format ) + if (srcimg->format != metadata.format) { result.Release(); return E_FAIL; } - if ( (srcimg->width > UINT32_MAX) || (srcimg->height > UINT32_MAX) ) + if ((srcimg->width > UINT32_MAX) || (srcimg->height > UINT32_MAX)) { result.Release(); return E_FAIL; } - if ( usewic ) + if (usewic) { - if ( wicpf ) + if (wicpf) { // Case 1: Source format is supported by Windows Imaging Component - hr = _PerformResizeUsingWIC( *srcimg, filter, pfGUID, *destimg ); + hr = PerformResizeUsingWIC(*srcimg, filter, pfGUID, *destimg); } else { // Case 2: Source format is not supported by WIC, so we have to convert, resize, and convert back - hr = _PerformResizeViaF32( *srcimg, filter, *destimg ); + hr = PerformResizeViaF32(*srcimg, filter, *destimg); } } else { // Case 3: not using WIC resizing - hr = _PerformResizeUsingCustomFilters( *srcimg, filter, *destimg ); + hr = PerformResizeUsingCustomFilters(*srcimg, filter, *destimg); } - if ( FAILED(hr) ) + if (FAILED(hr)) { result.Release(); return hr; @@ -974,57 +991,57 @@ HRESULT Resize( const Image* srcImages, size_t nimages, const TexMetadata& metad break; case TEX_DIMENSION_TEXTURE3D: - assert( metadata.arraySize == 1 ); + assert(metadata.arraySize == 1); - for( size_t slice = 0; slice < metadata.depth; ++slice ) + for (size_t slice = 0; slice < metadata.depth; ++slice) { - size_t srcIndex = metadata.ComputeIndex( 0, 0, slice ); - if ( srcIndex >= nimages ) + size_t srcIndex = metadata.ComputeIndex(0, 0, slice); + if (srcIndex >= nimages) { result.Release(); return E_FAIL; } - const Image* srcimg = &srcImages[ srcIndex ]; - const Image* destimg = result.GetImage( 0, 0, slice ); - if ( !srcimg || !destimg ) + const Image* srcimg = &srcImages[srcIndex]; + const Image* destimg = result.GetImage(0, 0, slice); + if (!srcimg || !destimg) { result.Release(); return E_POINTER; } - if ( srcimg->format != metadata.format ) + if (srcimg->format != metadata.format) { result.Release(); return E_FAIL; } - if ( (srcimg->width > UINT32_MAX) || (srcimg->height > UINT32_MAX) ) + if ((srcimg->width > UINT32_MAX) || (srcimg->height > UINT32_MAX)) { result.Release(); return E_FAIL; } - if ( usewic ) + if (usewic) { - if ( wicpf ) + if (wicpf) { // Case 1: Source format is supported by Windows Imaging Component - hr = _PerformResizeUsingWIC( *srcimg, filter, pfGUID, *destimg ); + hr = PerformResizeUsingWIC(*srcimg, filter, pfGUID, *destimg); } else { // Case 2: Source format is not supported by WIC, so we have to convert, resize, and convert back - hr = _PerformResizeViaF32( *srcimg, filter, *destimg ); + hr = PerformResizeViaF32(*srcimg, filter, *destimg); } } else { // Case 3: not using WIC resizing - hr = _PerformResizeUsingCustomFilters( *srcimg, filter, *destimg ); + hr = PerformResizeUsingCustomFilters(*srcimg, filter, *destimg); } - if ( FAILED(hr) ) + if (FAILED(hr)) { result.Release(); return hr; @@ -1039,5 +1056,3 @@ HRESULT Resize( const Image* srcImages, size_t nimages, const TexMetadata& metad return S_OK; } - -}; // namespace diff --git a/DirectXTex/DirectXTexTGA.cpp b/DirectXTex/DirectXTexTGA.cpp index 2b458ef..8f9b6d4 100644 --- a/DirectXTex/DirectXTexTGA.cpp +++ b/DirectXTex/DirectXTexTGA.cpp @@ -23,363 +23,373 @@ // * Always writes uncompressed files (i.e. can read RLE compression, but does not write it) // -enum TGAImageType -{ - TGA_NO_IMAGE = 0, - TGA_COLOR_MAPPED = 1, - TGA_TRUECOLOR = 2, - TGA_BLACK_AND_WHITE = 3, - TGA_COLOR_MAPPED_RLE = 9, - TGA_TRUECOLOR_RLE = 10, - TGA_BLACK_AND_WHITE_RLE = 11, -}; +using namespace DirectX; -enum TGADescriptorFlags +namespace { - TGA_FLAGS_INVERTX = 0x10, - TGA_FLAGS_INVERTY = 0x20, - TGA_FLAGS_INTERLEAVED_2WAY = 0x40, // Deprecated - TGA_FLAGS_INTERLEAVED_4WAY = 0x80, // Deprecated -}; + enum TGAImageType + { + TGA_NO_IMAGE = 0, + TGA_COLOR_MAPPED = 1, + TGA_TRUECOLOR = 2, + TGA_BLACK_AND_WHITE = 3, + TGA_COLOR_MAPPED_RLE = 9, + TGA_TRUECOLOR_RLE = 10, + TGA_BLACK_AND_WHITE_RLE = 11, + }; -const char* g_TGA20_Signature = "TRUEVISION-XFILE."; + enum TGADescriptorFlags + { + TGA_FLAGS_INVERTX = 0x10, + TGA_FLAGS_INVERTY = 0x20, + TGA_FLAGS_INTERLEAVED_2WAY = 0x40, // Deprecated + TGA_FLAGS_INTERLEAVED_4WAY = 0x80, // Deprecated + }; + + const char* g_TGA20_Signature = "TRUEVISION-XFILE."; #pragma pack(push,1) -struct TGA_HEADER -{ - uint8_t bIDLength; - uint8_t bColorMapType; - uint8_t bImageType; - uint16_t wColorMapFirst; - uint16_t wColorMapLength; - uint8_t bColorMapSize; - uint16_t wXOrigin; - uint16_t wYOrigin; - uint16_t wWidth; - uint16_t wHeight; - uint8_t bBitsPerPixel; - uint8_t bDescriptor; -}; + struct TGA_HEADER + { + uint8_t bIDLength; + uint8_t bColorMapType; + uint8_t bImageType; + uint16_t wColorMapFirst; + uint16_t wColorMapLength; + uint8_t bColorMapSize; + uint16_t wXOrigin; + uint16_t wYOrigin; + uint16_t wWidth; + uint16_t wHeight; + uint8_t bBitsPerPixel; + uint8_t bDescriptor; + }; -struct TGA_FOOTER -{ - uint16_t dwExtensionOffset; - uint16_t dwDeveloperOffset; - char Signature[18]; -}; + struct TGA_FOOTER + { + uint16_t dwExtensionOffset; + uint16_t dwDeveloperOffset; + char Signature[18]; + }; -struct TGA_EXTENSION -{ - uint16_t wSize; - char szAuthorName[41]; - char szAuthorComment[324]; - uint16_t wStampMonth; - uint16_t wStampDay; - uint16_t wStampYear; - uint16_t wStampHour; - uint16_t wStampMinute; - uint16_t wStampSecond; - char szJobName[41]; - uint16_t wJobHour; - uint16_t wJobMinute; - uint16_t wJobSecond; - char szSoftwareId[41]; - uint16_t wVersionNumber; - uint8_t bVersionLetter; - uint32_t dwKeyColor; - uint16_t wPixelNumerator; - uint16_t wPixelDenominator; - uint16_t wGammaNumerator; - uint16_t wGammaDenominator; - uint32_t dwColorOffset; - uint32_t dwStampOffset; - uint32_t dwScanOffset; - uint8_t bAttributesType; -}; + struct TGA_EXTENSION + { + uint16_t wSize; + char szAuthorName[41]; + char szAuthorComment[324]; + uint16_t wStampMonth; + uint16_t wStampDay; + uint16_t wStampYear; + uint16_t wStampHour; + uint16_t wStampMinute; + uint16_t wStampSecond; + char szJobName[41]; + uint16_t wJobHour; + uint16_t wJobMinute; + uint16_t wJobSecond; + char szSoftwareId[41]; + uint16_t wVersionNumber; + uint8_t bVersionLetter; + uint32_t dwKeyColor; + uint16_t wPixelNumerator; + uint16_t wPixelDenominator; + uint16_t wGammaNumerator; + uint16_t wGammaDenominator; + uint32_t dwColorOffset; + uint32_t dwStampOffset; + uint32_t dwScanOffset; + uint8_t bAttributesType; + }; #pragma pack(pop) -enum CONVERSION_FLAGS -{ - CONV_FLAGS_NONE = 0x0, - CONV_FLAGS_EXPAND = 0x1, // Conversion requires expanded pixel size - CONV_FLAGS_INVERTX = 0x2, // If set, scanlines are right-to-left - CONV_FLAGS_INVERTY = 0x4, // If set, scanlines are top-to-bottom - CONV_FLAGS_RLE = 0x8, // Source data is RLE compressed - - CONV_FLAGS_SWIZZLE = 0x10000, // Swizzle BGR<->RGB data - CONV_FLAGS_888 = 0x20000, // 24bpp format -}; - -namespace DirectX -{ - -//------------------------------------------------------------------------------------- -// Decodes TGA header -//------------------------------------------------------------------------------------- -static HRESULT _DecodeTGAHeader( _In_reads_bytes_(size) LPCVOID pSource, size_t size, _Out_ TexMetadata& metadata, size_t& offset, - _Inout_opt_ DWORD* convFlags ) -{ - if ( !pSource ) - return E_INVALIDARG; - - memset( &metadata, 0, sizeof(TexMetadata) ); - - if ( size < sizeof(TGA_HEADER) ) + enum CONVERSION_FLAGS { - return HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); - } + CONV_FLAGS_NONE = 0x0, + CONV_FLAGS_EXPAND = 0x1, // Conversion requires expanded pixel size + CONV_FLAGS_INVERTX = 0x2, // If set, scanlines are right-to-left + CONV_FLAGS_INVERTY = 0x4, // If set, scanlines are top-to-bottom + CONV_FLAGS_RLE = 0x8, // Source data is RLE compressed - auto pHeader = reinterpret_cast( pSource ); + CONV_FLAGS_SWIZZLE = 0x10000, // Swizzle BGR<->RGB data + CONV_FLAGS_888 = 0x20000, // 24bpp format + }; - if ( pHeader->bColorMapType != 0 - || pHeader->wColorMapLength != 0 ) - { - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); - } - if ( pHeader->bDescriptor & (TGA_FLAGS_INTERLEAVED_2WAY|TGA_FLAGS_INTERLEAVED_4WAY) ) + //------------------------------------------------------------------------------------- + // Decodes TGA header + //------------------------------------------------------------------------------------- + HRESULT DecodeTGAHeader( + _In_reads_bytes_(size) const void* pSource, + size_t size, + _Out_ TexMetadata& metadata, + size_t& offset, + _Inout_opt_ DWORD* convFlags) { - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); - } + if (!pSource) + return E_INVALIDARG; - if ( !pHeader->wWidth || !pHeader->wHeight ) - { - return HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); - } - - switch ( pHeader->bImageType ) - { - case TGA_TRUECOLOR: - case TGA_TRUECOLOR_RLE: - switch( pHeader->bBitsPerPixel ) + memset(&metadata, 0, sizeof(TexMetadata)); + + if (size < sizeof(TGA_HEADER)) { - case 16: - metadata.format = DXGI_FORMAT_B5G5R5A1_UNORM; - break; - - case 24: - metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM; - if ( convFlags ) - *convFlags |= CONV_FLAGS_EXPAND; - // We could use DXGI_FORMAT_B8G8R8X8_UNORM, but we prefer DXGI 1.0 formats - break; - - case 32: - metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM; - // We could use DXGI_FORMAT_B8G8R8A8_UNORM, but we prefer DXGI 1.0 formats - break; + return HRESULT_FROM_WIN32(ERROR_INVALID_DATA); } - if ( convFlags && (pHeader->bImageType == TGA_TRUECOLOR_RLE) ) - { - *convFlags |= CONV_FLAGS_RLE; - } - break; + auto pHeader = reinterpret_cast(pSource); - case TGA_BLACK_AND_WHITE: - case TGA_BLACK_AND_WHITE_RLE: - switch( pHeader->bBitsPerPixel ) + if (pHeader->bColorMapType != 0 + || pHeader->wColorMapLength != 0) { - case 8: - metadata.format = DXGI_FORMAT_R8_UNORM; + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + if (pHeader->bDescriptor & (TGA_FLAGS_INTERLEAVED_2WAY | TGA_FLAGS_INTERLEAVED_4WAY)) + { + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + if (!pHeader->wWidth || !pHeader->wHeight) + { + return HRESULT_FROM_WIN32(ERROR_INVALID_DATA); + } + + switch (pHeader->bImageType) + { + case TGA_TRUECOLOR: + case TGA_TRUECOLOR_RLE: + switch (pHeader->bBitsPerPixel) + { + case 16: + metadata.format = DXGI_FORMAT_B5G5R5A1_UNORM; + break; + + case 24: + metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM; + if (convFlags) + *convFlags |= CONV_FLAGS_EXPAND; + // We could use DXGI_FORMAT_B8G8R8X8_UNORM, but we prefer DXGI 1.0 formats + break; + + case 32: + metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM; + // We could use DXGI_FORMAT_B8G8R8A8_UNORM, but we prefer DXGI 1.0 formats + break; + } + + if (convFlags && (pHeader->bImageType == TGA_TRUECOLOR_RLE)) + { + *convFlags |= CONV_FLAGS_RLE; + } break; + case TGA_BLACK_AND_WHITE: + case TGA_BLACK_AND_WHITE_RLE: + switch (pHeader->bBitsPerPixel) + { + case 8: + metadata.format = DXGI_FORMAT_R8_UNORM; + break; + + default: + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + if (convFlags && (pHeader->bImageType == TGA_BLACK_AND_WHITE_RLE)) + { + *convFlags |= CONV_FLAGS_RLE; + } + break; + + case TGA_NO_IMAGE: + case TGA_COLOR_MAPPED: + case TGA_COLOR_MAPPED_RLE: + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + default: - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + return HRESULT_FROM_WIN32(ERROR_INVALID_DATA); } - if ( convFlags && (pHeader->bImageType == TGA_BLACK_AND_WHITE_RLE) ) + metadata.width = pHeader->wWidth; + metadata.height = pHeader->wHeight; + metadata.depth = metadata.arraySize = metadata.mipLevels = 1; + metadata.dimension = TEX_DIMENSION_TEXTURE2D; + + if (convFlags) { - *convFlags |= CONV_FLAGS_RLE; + if (pHeader->bDescriptor & TGA_FLAGS_INVERTX) + *convFlags |= CONV_FLAGS_INVERTX; + + if (pHeader->bDescriptor & TGA_FLAGS_INVERTY) + *convFlags |= CONV_FLAGS_INVERTY; } - break; - case TGA_NO_IMAGE: - case TGA_COLOR_MAPPED: - case TGA_COLOR_MAPPED_RLE: - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + offset = sizeof(TGA_HEADER); - default: - return HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); - } - - metadata.width = pHeader->wWidth; - metadata.height = pHeader->wHeight; - metadata.depth = metadata.arraySize = metadata.mipLevels = 1; - metadata.dimension = TEX_DIMENSION_TEXTURE2D; - - if ( convFlags ) - { - if ( pHeader->bDescriptor & TGA_FLAGS_INVERTX ) - *convFlags |= CONV_FLAGS_INVERTX; - - if ( pHeader->bDescriptor & TGA_FLAGS_INVERTY ) - *convFlags |= CONV_FLAGS_INVERTY; - } - - offset = sizeof( TGA_HEADER ); - - if ( pHeader->bIDLength != 0 ) - { - offset += pHeader->bIDLength; - } - - return S_OK; -} - - -//------------------------------------------------------------------------------------- -// Set alpha for images with all 0 alpha channel -//------------------------------------------------------------------------------------- -static HRESULT _SetAlphaChannelToOpaque( _In_ const Image* image ) -{ - assert( image ); - - auto pPixels = reinterpret_cast( image->pixels ); - if ( !pPixels ) - return E_POINTER; - - for( size_t y = 0; y < image->height; ++y ) - { - _CopyScanline( pPixels, image->rowPitch, pPixels, image->rowPitch, image->format, TEXP_SCANLINE_SETALPHA ); - pPixels += image->rowPitch; - } - - return S_OK; -} - - -//------------------------------------------------------------------------------------- -// Uncompress pixel data from a TGA into the target image -//------------------------------------------------------------------------------------- -static HRESULT _UncompressPixels( _In_reads_bytes_(size) LPCVOID pSource, size_t size, _In_ const Image* image, _In_ DWORD convFlags ) -{ - assert( pSource && size > 0 ); - - if ( !image || !image->pixels ) - return E_POINTER; - - // Compute TGA image data pitch - size_t rowPitch; - if ( convFlags & CONV_FLAGS_EXPAND ) - { - rowPitch = image->width * 3; - } - else - { - size_t slicePitch; - ComputePitch( image->format, image->width, image->height, rowPitch, slicePitch, CP_FLAGS_NONE ); - } - - auto sPtr = reinterpret_cast( pSource ); - const uint8_t* endPtr = sPtr + size; - - switch( image->format ) - { - //--------------------------------------------------------------------------- 8-bit - case DXGI_FORMAT_R8_UNORM: - for( size_t y=0; y < image->height; ++y ) + if (pHeader->bIDLength != 0) { - size_t offset = ( (convFlags & CONV_FLAGS_INVERTX ) ? (image->width - 1) : 0 ); - assert( offset < rowPitch); + offset += pHeader->bIDLength; + } - uint8_t* dPtr = reinterpret_cast( image->pixels ) - + ( image->rowPitch * ( (convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1) ) ) - + offset; + return S_OK; + } - for( size_t x=0; x < image->width; ) + + //------------------------------------------------------------------------------------- + // Set alpha for images with all 0 alpha channel + //------------------------------------------------------------------------------------- + HRESULT SetAlphaChannelToOpaque(_In_ const Image* image) + { + assert(image); + + auto pPixels = reinterpret_cast(image->pixels); + if (!pPixels) + return E_POINTER; + + for (size_t y = 0; y < image->height; ++y) + { + _CopyScanline(pPixels, image->rowPitch, pPixels, image->rowPitch, image->format, TEXP_SCANLINE_SETALPHA); + pPixels += image->rowPitch; + } + + return S_OK; + } + + + //------------------------------------------------------------------------------------- + // Uncompress pixel data from a TGA into the target image + //------------------------------------------------------------------------------------- + HRESULT UncompressPixels( + _In_reads_bytes_(size) const void* pSource, + size_t size, + _In_ const Image* image, + _In_ DWORD convFlags) + { + assert(pSource && size > 0); + + if (!image || !image->pixels) + return E_POINTER; + + // Compute TGA image data pitch + size_t rowPitch; + if (convFlags & CONV_FLAGS_EXPAND) + { + rowPitch = image->width * 3; + } + else + { + size_t slicePitch; + ComputePitch(image->format, image->width, image->height, rowPitch, slicePitch, CP_FLAGS_NONE); + } + + auto sPtr = reinterpret_cast(pSource); + const uint8_t* endPtr = sPtr + size; + + switch (image->format) + { + //--------------------------------------------------------------------------- 8-bit + case DXGI_FORMAT_R8_UNORM: + for (size_t y = 0; y < image->height; ++y) { - if ( sPtr >= endPtr ) - return E_FAIL; + size_t offset = ((convFlags & CONV_FLAGS_INVERTX) ? (image->width - 1) : 0); + assert(offset < rowPitch); - if ( *sPtr & 0x80 ) + uint8_t* dPtr = reinterpret_cast(image->pixels) + + (image->rowPitch * ((convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1))) + + offset; + + for (size_t x = 0; x < image->width; ) { - // Repeat - size_t j = (*sPtr & 0x7F) + 1; - if ( ++sPtr >= endPtr ) + if (sPtr >= endPtr) return E_FAIL; - for( ; j > 0; --j, ++x ) + if (*sPtr & 0x80) { - if ( x >= image->width ) + // Repeat + size_t j = (*sPtr & 0x7F) + 1; + if (++sPtr >= endPtr) return E_FAIL; - *dPtr = *sPtr; + for (; j > 0; --j, ++x) + { + if (x >= image->width) + return E_FAIL; - if ( convFlags & CONV_FLAGS_INVERTX ) - --dPtr; - else - ++dPtr; + *dPtr = *sPtr; + + if (convFlags & CONV_FLAGS_INVERTX) + --dPtr; + else + ++dPtr; + } + + ++sPtr; } - - ++sPtr; - } - else - { - // Literal - size_t j = (*sPtr & 0x7F) + 1; - ++sPtr; - - if ( sPtr+j > endPtr ) - return E_FAIL; - - for( ; j > 0; --j, ++x ) + else { - if ( x >= image->width ) + // Literal + size_t j = (*sPtr & 0x7F) + 1; + ++sPtr; + + if (sPtr + j > endPtr) return E_FAIL; - *dPtr = *(sPtr++); + for (; j > 0; --j, ++x) + { + if (x >= image->width) + return E_FAIL; - if ( convFlags & CONV_FLAGS_INVERTX ) - --dPtr; - else - ++dPtr; + *dPtr = *(sPtr++); + + if (convFlags & CONV_FLAGS_INVERTX) + --dPtr; + else + ++dPtr; + } } } } - } - break; + break; - //-------------------------------------------------------------------------- 16-bit - case DXGI_FORMAT_B5G5R5A1_UNORM: + //-------------------------------------------------------------------------- 16-bit + case DXGI_FORMAT_B5G5R5A1_UNORM: { bool nonzeroa = false; - for( size_t y=0; y < image->height; ++y ) + for (size_t y = 0; y < image->height; ++y) { - size_t offset = ( (convFlags & CONV_FLAGS_INVERTX ) ? (image->width - 1) : 0 ); - assert( offset*2 < rowPitch); + size_t offset = ((convFlags & CONV_FLAGS_INVERTX) ? (image->width - 1) : 0); + assert(offset * 2 < rowPitch); - uint16_t* dPtr = reinterpret_cast( reinterpret_cast( image->pixels ) - + ( image->rowPitch * ( (convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1) ) ) ) - + offset; + uint16_t* dPtr = reinterpret_cast(reinterpret_cast(image->pixels) + + (image->rowPitch * ((convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1)))) + + offset; - for( size_t x=0; x < image->width; ) + for (size_t x = 0; x < image->width; ) { - if ( sPtr >= endPtr ) + if (sPtr >= endPtr) return E_FAIL; - if ( *sPtr & 0x80 ) + if (*sPtr & 0x80) { // Repeat size_t j = (*sPtr & 0x7F) + 1; ++sPtr; - if ( sPtr+1 >= endPtr ) + if (sPtr + 1 >= endPtr) return E_FAIL; - uint16_t t = *sPtr | (*(sPtr+1) << 8); - if ( t & 0x8000 ) + uint16_t t = *sPtr | (*(sPtr + 1) << 8); + if (t & 0x8000) nonzeroa = true; sPtr += 2; - for( ; j > 0; --j, ++x ) + for (; j > 0; --j, ++x) { - if ( x >= image->width ) + if (x >= image->width) return E_FAIL; *dPtr = t; - if ( convFlags & CONV_FLAGS_INVERTX ) + if (convFlags & CONV_FLAGS_INVERTX) --dPtr; else ++dPtr; @@ -391,21 +401,21 @@ static HRESULT _UncompressPixels( _In_reads_bytes_(size) LPCVOID pSource, size_t size_t j = (*sPtr & 0x7F) + 1; ++sPtr; - if ( sPtr+(j*2) > endPtr ) + if (sPtr + (j * 2) > endPtr) return E_FAIL; - for( ; j > 0; --j, ++x ) + for (; j > 0; --j, ++x) { - if ( x >= image->width ) + if (x >= image->width) return E_FAIL; - uint16_t t = *sPtr | (*(sPtr+1) << 8); - if ( t & 0x8000 ) + uint16_t t = *sPtr | (*(sPtr + 1) << 8); + if (t & 0x8000) nonzeroa = true; sPtr += 2; *dPtr = t; - if ( convFlags & CONV_FLAGS_INVERTX ) + if (convFlags & CONV_FLAGS_INVERTX) --dPtr; else ++dPtr; @@ -415,76 +425,76 @@ static HRESULT _UncompressPixels( _In_reads_bytes_(size) LPCVOID pSource, size_t } // If there are no non-zero alpha channel entries, we'll assume alpha is not used and force it to opaque - if ( !nonzeroa ) + if (!nonzeroa) { - HRESULT hr = _SetAlphaChannelToOpaque( image ); - if ( FAILED(hr) ) + HRESULT hr = SetAlphaChannelToOpaque(image); + if (FAILED(hr)) return hr; } } break; - //----------------------------------------------------------------------- 24/32-bit - case DXGI_FORMAT_R8G8B8A8_UNORM: + //----------------------------------------------------------------------- 24/32-bit + case DXGI_FORMAT_R8G8B8A8_UNORM: { bool nonzeroa = false; - for( size_t y=0; y < image->height; ++y ) + for (size_t y = 0; y < image->height; ++y) { - size_t offset = ( (convFlags & CONV_FLAGS_INVERTX ) ? (image->width - 1) : 0 ); + size_t offset = ((convFlags & CONV_FLAGS_INVERTX) ? (image->width - 1) : 0); - uint32_t* dPtr = reinterpret_cast( reinterpret_cast( image->pixels ) - + ( image->rowPitch * ( (convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1) ) ) ) - + offset; + uint32_t* dPtr = reinterpret_cast(reinterpret_cast(image->pixels) + + (image->rowPitch * ((convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1)))) + + offset; - for( size_t x=0; x < image->width; ) + for (size_t x = 0; x < image->width; ) { - if ( sPtr >= endPtr ) + if (sPtr >= endPtr) return E_FAIL; - if ( *sPtr & 0x80 ) + if (*sPtr & 0x80) { // Repeat size_t j = (*sPtr & 0x7F) + 1; ++sPtr; DWORD t; - if ( convFlags & CONV_FLAGS_EXPAND ) + if (convFlags & CONV_FLAGS_EXPAND) { - assert( offset*3 < rowPitch); + assert(offset * 3 < rowPitch); - if ( sPtr+2 >= endPtr ) + if (sPtr + 2 >= endPtr) return E_FAIL; // BGR -> RGBA - t = ( *sPtr << 16 ) | ( *(sPtr+1) << 8 ) | ( *(sPtr+2) ) | 0xFF000000; + t = (*sPtr << 16) | (*(sPtr + 1) << 8) | (*(sPtr + 2)) | 0xFF000000; sPtr += 3; nonzeroa = true; } else { - assert( offset*4 < rowPitch); + assert(offset * 4 < rowPitch); - if ( sPtr+3 >= endPtr ) + if (sPtr + 3 >= endPtr) return E_FAIL; // BGRA -> RGBA - t = ( *sPtr << 16 ) | ( *(sPtr+1) << 8 ) | ( *(sPtr+2) ) | ( *(sPtr+3) << 24 ); + t = (*sPtr << 16) | (*(sPtr + 1) << 8) | (*(sPtr + 2)) | (*(sPtr + 3) << 24); - if ( *(sPtr+3) > 0 ) + if (*(sPtr + 3) > 0) nonzeroa = true; sPtr += 4; } - for( ; j > 0; --j, ++x ) + for (; j > 0; --j, ++x) { - if ( x >= image->width ) + if (x >= image->width) return E_FAIL; *dPtr = t; - if ( convFlags & CONV_FLAGS_INVERTX ) + if (convFlags & CONV_FLAGS_INVERTX) --dPtr; else ++dPtr; @@ -496,52 +506,52 @@ static HRESULT _UncompressPixels( _In_reads_bytes_(size) LPCVOID pSource, size_t size_t j = (*sPtr & 0x7F) + 1; ++sPtr; - if ( convFlags & CONV_FLAGS_EXPAND ) + if (convFlags & CONV_FLAGS_EXPAND) { - if ( sPtr+(j*3) > endPtr ) + if (sPtr + (j * 3) > endPtr) return E_FAIL; } else { - if ( sPtr+(j*4) > endPtr ) + if (sPtr + (j * 4) > endPtr) return E_FAIL; } - for( ; j > 0; --j, ++x ) + for (; j > 0; --j, ++x) { - if ( x >= image->width ) + if (x >= image->width) return E_FAIL; - if ( convFlags & CONV_FLAGS_EXPAND ) + if (convFlags & CONV_FLAGS_EXPAND) { - assert( offset*3 < rowPitch); + assert(offset * 3 < rowPitch); - if ( sPtr+2 >= endPtr ) + if (sPtr + 2 >= endPtr) return E_FAIL; // BGR -> RGBA - *dPtr = ( *sPtr << 16 ) | ( *(sPtr+1) << 8 ) | ( *(sPtr+2) ) | 0xFF000000; + *dPtr = (*sPtr << 16) | (*(sPtr + 1) << 8) | (*(sPtr + 2)) | 0xFF000000; sPtr += 3; nonzeroa = true; } else { - assert( offset*4 < rowPitch); + assert(offset * 4 < rowPitch); - if ( sPtr+3 >= endPtr ) + if (sPtr + 3 >= endPtr) return E_FAIL; // BGRA -> RGBA - *dPtr = ( *sPtr << 16 ) | ( *(sPtr+1) << 8 ) | ( *(sPtr+2) ) | ( *(sPtr+3) << 24 ); + *dPtr = (*sPtr << 16) | (*(sPtr + 1) << 8) | (*(sPtr + 2)) | (*(sPtr + 3) << 24); - if ( *(sPtr+3) > 0 ) + if (*(sPtr + 3) > 0) nonzeroa = true; sPtr += 4; } - if ( convFlags & CONV_FLAGS_INVERTX ) + if (convFlags & CONV_FLAGS_INVERTX) --dPtr; else ++dPtr; @@ -551,103 +561,107 @@ static HRESULT _UncompressPixels( _In_reads_bytes_(size) LPCVOID pSource, size_t } // If there are no non-zero alpha channel entries, we'll assume alpha is not used and force it to opaque - if ( !nonzeroa ) + if (!nonzeroa) { - HRESULT hr = _SetAlphaChannelToOpaque( image ); - if ( FAILED(hr) ) + HRESULT hr = SetAlphaChannelToOpaque(image); + if (FAILED(hr)) return hr; } } break; - //--------------------------------------------------------------------------------- - default: - return E_FAIL; - } - - return S_OK; -} - - -//------------------------------------------------------------------------------------- -// Copies pixel data from a TGA into the target image -//------------------------------------------------------------------------------------- -static HRESULT _CopyPixels( _In_reads_bytes_(size) LPCVOID pSource, size_t size, _In_ const Image* image, _In_ DWORD convFlags ) -{ - assert( pSource && size > 0 ); - - if ( !image || !image->pixels ) - return E_POINTER; - - // Compute TGA image data pitch - size_t rowPitch; - if ( convFlags & CONV_FLAGS_EXPAND ) - { - rowPitch = image->width * 3; - } - else - { - size_t slicePitch; - ComputePitch( image->format, image->width, image->height, rowPitch, slicePitch, CP_FLAGS_NONE ); - } - - const uint8_t* sPtr = reinterpret_cast( pSource ); - const uint8_t* endPtr = sPtr + size; - - switch( image->format ) - { - //--------------------------------------------------------------------------- 8-bit - case DXGI_FORMAT_R8_UNORM: - for( size_t y=0; y < image->height; ++y ) - { - size_t offset = ( (convFlags & CONV_FLAGS_INVERTX ) ? (image->width - 1) : 0 ); - assert( offset < rowPitch); - - uint8_t* dPtr = reinterpret_cast( image->pixels ) - + ( image->rowPitch * ( (convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1) ) ) - + offset; - - for( size_t x=0; x < image->width; ++x ) - { - if ( sPtr >= endPtr ) - return E_FAIL; - - *dPtr = *(sPtr++); - - if ( convFlags & CONV_FLAGS_INVERTX ) - --dPtr; - else - ++dPtr; - } + //--------------------------------------------------------------------------------- + default: + return E_FAIL; } - break; - //-------------------------------------------------------------------------- 16-bit - case DXGI_FORMAT_B5G5R5A1_UNORM: + return S_OK; + } + + + //------------------------------------------------------------------------------------- + // Copies pixel data from a TGA into the target image + //------------------------------------------------------------------------------------- + HRESULT CopyPixels( + _In_reads_bytes_(size) const void* pSource, + size_t size, + _In_ const Image* image, + _In_ DWORD convFlags) + { + assert(pSource && size > 0); + + if (!image || !image->pixels) + return E_POINTER; + + // Compute TGA image data pitch + size_t rowPitch; + if (convFlags & CONV_FLAGS_EXPAND) { - bool nonzeroa = false; - for( size_t y=0; y < image->height; ++y ) + rowPitch = image->width * 3; + } + else + { + size_t slicePitch; + ComputePitch(image->format, image->width, image->height, rowPitch, slicePitch, CP_FLAGS_NONE); + } + + const uint8_t* sPtr = reinterpret_cast(pSource); + const uint8_t* endPtr = sPtr + size; + + switch (image->format) + { + //--------------------------------------------------------------------------- 8-bit + case DXGI_FORMAT_R8_UNORM: + for (size_t y = 0; y < image->height; ++y) { - size_t offset = ( (convFlags & CONV_FLAGS_INVERTX ) ? (image->width - 1) : 0 ); - assert( offset*2 < rowPitch); + size_t offset = ((convFlags & CONV_FLAGS_INVERTX) ? (image->width - 1) : 0); + assert(offset < rowPitch); - uint16_t* dPtr = reinterpret_cast( reinterpret_cast( image->pixels ) - + ( image->rowPitch * ( (convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1) ) ) ) - + offset; + uint8_t* dPtr = reinterpret_cast(image->pixels) + + (image->rowPitch * ((convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1))) + + offset; - for( size_t x=0; x < image->width; ++x ) + for (size_t x = 0; x < image->width; ++x) { - if ( sPtr+1 >= endPtr ) + if (sPtr >= endPtr) return E_FAIL; - uint16_t t = *sPtr | (*(sPtr+1) << 8); + *dPtr = *(sPtr++); + + if (convFlags & CONV_FLAGS_INVERTX) + --dPtr; + else + ++dPtr; + } + } + break; + + //-------------------------------------------------------------------------- 16-bit + case DXGI_FORMAT_B5G5R5A1_UNORM: + { + bool nonzeroa = false; + for (size_t y = 0; y < image->height; ++y) + { + size_t offset = ((convFlags & CONV_FLAGS_INVERTX) ? (image->width - 1) : 0); + assert(offset * 2 < rowPitch); + + uint16_t* dPtr = reinterpret_cast(reinterpret_cast(image->pixels) + + (image->rowPitch * ((convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1)))) + + offset; + + for (size_t x = 0; x < image->width; ++x) + { + if (sPtr + 1 >= endPtr) + return E_FAIL; + + uint16_t t = *sPtr | (*(sPtr + 1) << 8); sPtr += 2; *dPtr = t; - if ( t & 0x8000 ) + if (t & 0x8000) nonzeroa = true; - if ( convFlags & CONV_FLAGS_INVERTX ) + if (convFlags & CONV_FLAGS_INVERTX) --dPtr; else ++dPtr; @@ -655,59 +669,59 @@ static HRESULT _CopyPixels( _In_reads_bytes_(size) LPCVOID pSource, size_t size, } // If there are no non-zero alpha channel entries, we'll assume alpha is not used and force it to opaque - if ( !nonzeroa ) + if (!nonzeroa) { - HRESULT hr = _SetAlphaChannelToOpaque( image ); - if ( FAILED(hr) ) + HRESULT hr = SetAlphaChannelToOpaque(image); + if (FAILED(hr)) return hr; } } break; - //----------------------------------------------------------------------- 24/32-bit - case DXGI_FORMAT_R8G8B8A8_UNORM: + //----------------------------------------------------------------------- 24/32-bit + case DXGI_FORMAT_R8G8B8A8_UNORM: { bool nonzeroa = false; - for( size_t y=0; y < image->height; ++y ) + for (size_t y = 0; y < image->height; ++y) { - size_t offset = ( (convFlags & CONV_FLAGS_INVERTX ) ? (image->width - 1) : 0 ); + size_t offset = ((convFlags & CONV_FLAGS_INVERTX) ? (image->width - 1) : 0); - uint32_t* dPtr = reinterpret_cast( reinterpret_cast( image->pixels ) - + ( image->rowPitch * ( (convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1) ) ) ) - + offset; + uint32_t* dPtr = reinterpret_cast(reinterpret_cast(image->pixels) + + (image->rowPitch * ((convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1)))) + + offset; - for( size_t x=0; x < image->width; ++x ) + for (size_t x = 0; x < image->width; ++x) { - if ( convFlags & CONV_FLAGS_EXPAND ) + if (convFlags & CONV_FLAGS_EXPAND) { - assert( offset*3 < rowPitch); + assert(offset * 3 < rowPitch); - if ( sPtr+2 >= endPtr ) + if (sPtr + 2 >= endPtr) return E_FAIL; // BGR -> RGBA - *dPtr = ( *sPtr << 16 ) | ( *(sPtr+1) << 8 ) | ( *(sPtr+2) ) | 0xFF000000; + *dPtr = (*sPtr << 16) | (*(sPtr + 1) << 8) | (*(sPtr + 2)) | 0xFF000000; sPtr += 3; nonzeroa = true; } else { - assert( offset*4 < rowPitch); + assert(offset * 4 < rowPitch); - if ( sPtr+3 >= endPtr ) + if (sPtr + 3 >= endPtr) return E_FAIL; // BGRA -> RGBA - *dPtr = ( *sPtr << 16 ) | ( *(sPtr+1) << 8 ) | ( *(sPtr+2) ) | ( *(sPtr+3) << 24 ); + *dPtr = (*sPtr << 16) | (*(sPtr + 1) << 8) | (*(sPtr + 2)) | (*(sPtr + 3) << 24); - if ( *(sPtr+3) > 0 ) + if (*(sPtr + 3) > 0) nonzeroa = true; sPtr += 4; } - if ( convFlags & CONV_FLAGS_INVERTX ) + if (convFlags & CONV_FLAGS_INVERTX) --dPtr; else ++dPtr; @@ -715,115 +729,119 @@ static HRESULT _CopyPixels( _In_reads_bytes_(size) LPCVOID pSource, size_t size, } // If there are no non-zero alpha channel entries, we'll assume alpha is not used and force it to opaque - if ( !nonzeroa ) + if (!nonzeroa) { - HRESULT hr = _SetAlphaChannelToOpaque( image ); - if ( FAILED(hr) ) + HRESULT hr = SetAlphaChannelToOpaque(image); + if (FAILED(hr)) return hr; } } break; - //--------------------------------------------------------------------------------- - default: - return E_FAIL; + //--------------------------------------------------------------------------------- + default: + return E_FAIL; + } + + return S_OK; } - return S_OK; -} - -//------------------------------------------------------------------------------------- -// Encodes TGA file header -//------------------------------------------------------------------------------------- -static HRESULT _EncodeTGAHeader( _In_ const Image& image, _Out_ TGA_HEADER& header, _Inout_ DWORD& convFlags ) -{ - memset( &header, 0, sizeof(TGA_HEADER) ); - - if ( (image.width > 0xFFFF) - || (image.height > 0xFFFF) ) + //------------------------------------------------------------------------------------- + // Encodes TGA file header + //------------------------------------------------------------------------------------- + HRESULT EncodeTGAHeader(_In_ const Image& image, _Out_ TGA_HEADER& header, _Inout_ DWORD& convFlags) { - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); - } + memset(&header, 0, sizeof(TGA_HEADER)); - header.wWidth = static_cast( image.width ); - header.wHeight = static_cast( image.height ); - - switch( image.format ) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - header.bImageType = TGA_TRUECOLOR; - header.bBitsPerPixel = 32; - header.bDescriptor = TGA_FLAGS_INVERTY | 8; - convFlags |= CONV_FLAGS_SWIZZLE; - break; - - case DXGI_FORMAT_B8G8R8A8_UNORM: - case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: - header.bImageType = TGA_TRUECOLOR; - header.bBitsPerPixel = 32; - header.bDescriptor = TGA_FLAGS_INVERTY | 8; - break; - - case DXGI_FORMAT_B8G8R8X8_UNORM: - case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: - header.bImageType = TGA_TRUECOLOR; - header.bBitsPerPixel = 24; - header.bDescriptor = TGA_FLAGS_INVERTY; - convFlags |= CONV_FLAGS_888; - break; - - case DXGI_FORMAT_R8_UNORM: - case DXGI_FORMAT_A8_UNORM: - header.bImageType = TGA_BLACK_AND_WHITE; - header.bBitsPerPixel = 8; - header.bDescriptor = TGA_FLAGS_INVERTY; - break; - - case DXGI_FORMAT_B5G5R5A1_UNORM: - header.bImageType = TGA_TRUECOLOR; - header.bBitsPerPixel = 16; - header.bDescriptor = TGA_FLAGS_INVERTY | 1; - break; - - default: - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); - } - - return S_OK; -} - - -//------------------------------------------------------------------------------------- -// Copies BGRX data to form BGR 24bpp data -//------------------------------------------------------------------------------------- -#pragma warning(suppress: 6001 6101) // In the case where outSize is insufficient we do not write to pDestination -static void _Copy24bppScanline( _Out_writes_bytes_(outSize) LPVOID pDestination, _In_ size_t outSize, - _In_reads_bytes_(inSize) LPCVOID pSource, _In_ size_t inSize ) -{ - assert( pDestination && outSize > 0 ); - assert( pSource && inSize > 0 ); - - assert( pDestination != pSource ); - - const uint32_t * __restrict sPtr = reinterpret_cast(pSource); - uint8_t * __restrict dPtr = reinterpret_cast(pDestination); - - if ( inSize >= 4 && outSize >= 3 ) - { - const uint8_t* endPtr = dPtr + outSize; - - for( size_t count = 0; count < ( inSize - 3 ); count += 4 ) + if ((image.width > 0xFFFF) + || (image.height > 0xFFFF)) { - uint32_t t = *(sPtr++); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } - if ( dPtr+3 > endPtr ) - return; + header.wWidth = static_cast(image.width); + header.wHeight = static_cast(image.height); - *(dPtr++) = uint8_t(t & 0xFF); // Blue - *(dPtr++) = uint8_t((t & 0xFF00) >> 8); // Green - *(dPtr++) = uint8_t((t & 0xFF0000) >> 16); // Red + switch (image.format) + { + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + header.bImageType = TGA_TRUECOLOR; + header.bBitsPerPixel = 32; + header.bDescriptor = TGA_FLAGS_INVERTY | 8; + convFlags |= CONV_FLAGS_SWIZZLE; + break; + + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + header.bImageType = TGA_TRUECOLOR; + header.bBitsPerPixel = 32; + header.bDescriptor = TGA_FLAGS_INVERTY | 8; + break; + + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + header.bImageType = TGA_TRUECOLOR; + header.bBitsPerPixel = 24; + header.bDescriptor = TGA_FLAGS_INVERTY; + convFlags |= CONV_FLAGS_888; + break; + + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_A8_UNORM: + header.bImageType = TGA_BLACK_AND_WHITE; + header.bBitsPerPixel = 8; + header.bDescriptor = TGA_FLAGS_INVERTY; + break; + + case DXGI_FORMAT_B5G5R5A1_UNORM: + header.bImageType = TGA_TRUECOLOR; + header.bBitsPerPixel = 16; + header.bDescriptor = TGA_FLAGS_INVERTY | 1; + break; + + default: + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + return S_OK; + } + + + //------------------------------------------------------------------------------------- + // Copies BGRX data to form BGR 24bpp data + //------------------------------------------------------------------------------------- +#pragma warning(suppress: 6001 6101) // In the case where outSize is insufficient we do not write to pDestination + void Copy24bppScanline( + _Out_writes_bytes_(outSize) void* pDestination, + _In_ size_t outSize, + _In_reads_bytes_(inSize) const void* pSource, + _In_ size_t inSize) + { + assert(pDestination && outSize > 0); + assert(pSource && inSize > 0); + + assert(pDestination != pSource); + + const uint32_t * __restrict sPtr = reinterpret_cast(pSource); + uint8_t * __restrict dPtr = reinterpret_cast(pDestination); + + if (inSize >= 4 && outSize >= 3) + { + const uint8_t* endPtr = dPtr + outSize; + + for (size_t count = 0; count < (inSize - 3); count += 4) + { + uint32_t t = *(sPtr++); + + if (dPtr + 3 > endPtr) + return; + + *(dPtr++) = uint8_t(t & 0xFF); // Blue + *(dPtr++) = uint8_t((t & 0xFF00) >> 8); // Green + *(dPtr++) = uint8_t((t & 0xFF0000) >> 16); // Red + } } } } @@ -837,57 +855,50 @@ static void _Copy24bppScanline( _Out_writes_bytes_(outSize) LPVOID pDestination, // Obtain metadata from TGA file in memory/on disk //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT GetMetadataFromTGAMemory( LPCVOID pSource, size_t size, TexMetadata& metadata ) +HRESULT DirectX::GetMetadataFromTGAMemory( + const void* pSource, + size_t size, + TexMetadata& metadata ) { if ( !pSource || size == 0 ) return E_INVALIDARG; size_t offset; - return _DecodeTGAHeader( pSource, size, metadata, offset, 0 ); + return DecodeTGAHeader( pSource, size, metadata, offset, 0 ); } _Use_decl_annotations_ -HRESULT GetMetadataFromTGAFile( LPCWSTR szFile, TexMetadata& metadata ) +HRESULT DirectX::GetMetadataFromTGAFile(const wchar_t* szFile, TexMetadata& metadata) { - if ( !szFile ) + if (!szFile) return E_INVALIDARG; #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) - ScopedHandle hFile( safe_handle( CreateFile2( szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, 0 ) ) ); + ScopedHandle hFile(safe_handle(CreateFile2(szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr))); #else - ScopedHandle hFile( safe_handle( CreateFileW( szFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, - FILE_FLAG_SEQUENTIAL_SCAN, 0 ) ) ); + ScopedHandle hFile(safe_handle(CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, nullptr))); #endif - if ( !hFile ) + if (!hFile) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } // Get the file size - LARGE_INTEGER fileSize = {0}; - -#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) FILE_STANDARD_INFO fileInfo; - if ( !GetFileInformationByHandleEx( hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo) ) ) + if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo))) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } - fileSize = fileInfo.EndOfFile; -#else - if ( !GetFileSizeEx( hFile.get(), &fileSize ) ) - { - return HRESULT_FROM_WIN32( GetLastError() ); - } -#endif // File is too big for 32-bit allocation, so reject read (4 GB should be plenty large enough for a valid TGA file) - if ( fileSize.HighPart > 0 ) + if (fileInfo.EndOfFile.HighPart > 0) { - return HRESULT_FROM_WIN32( ERROR_FILE_TOO_LARGE ); + return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE); } // Need at least enough data to fill the standard header to be a valid TGA - if ( fileSize.LowPart < ( sizeof(TGA_HEADER) ) ) + if (fileInfo.EndOfFile.LowPart < (sizeof(TGA_HEADER))) { return E_FAIL; } @@ -895,13 +906,13 @@ HRESULT GetMetadataFromTGAFile( LPCWSTR szFile, TexMetadata& metadata ) // Read the standard header (we don't need the file footer to parse the file) uint8_t header[sizeof(TGA_HEADER)]; DWORD bytesRead = 0; - if ( !ReadFile( hFile.get(), header, sizeof(TGA_HEADER), &bytesRead, 0 ) ) + if (!ReadFile(hFile.get(), header, sizeof(TGA_HEADER), &bytesRead, nullptr)) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } size_t offset; - return _DecodeTGAHeader( header, bytesRead, metadata, offset, 0 ); + return DecodeTGAHeader(header, bytesRead, metadata, offset, 0); } @@ -909,9 +920,13 @@ HRESULT GetMetadataFromTGAFile( LPCWSTR szFile, TexMetadata& metadata ) // Load a TGA file in memory //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT LoadFromTGAMemory( LPCVOID pSource, size_t size, TexMetadata* metadata, ScratchImage& image ) +HRESULT DirectX::LoadFromTGAMemory( + const void* pSource, + size_t size, + TexMetadata* metadata, + ScratchImage& image) { - if ( !pSource || size == 0 ) + if (!pSource || size == 0) return E_INVALIDARG; image.Release(); @@ -919,40 +934,40 @@ HRESULT LoadFromTGAMemory( LPCVOID pSource, size_t size, TexMetadata* metadata, size_t offset; DWORD convFlags = 0; TexMetadata mdata; - HRESULT hr = _DecodeTGAHeader( pSource, size, mdata, offset, &convFlags ); - if ( FAILED(hr) ) + HRESULT hr = DecodeTGAHeader(pSource, size, mdata, offset, &convFlags); + if (FAILED(hr)) return hr; - if ( offset > size ) + if (offset > size) return E_FAIL; - auto pPixels = reinterpret_cast( reinterpret_cast(pSource) + offset ); + auto pPixels = reinterpret_cast(reinterpret_cast(pSource) + offset); size_t remaining = size - offset; - if ( remaining == 0 ) + if (remaining == 0) return E_FAIL; - hr = image.Initialize2D( mdata.format, mdata.width, mdata.height, 1, 1 ); - if ( FAILED(hr) ) + hr = image.Initialize2D(mdata.format, mdata.width, mdata.height, 1, 1); + if (FAILED(hr)) return hr; - if ( convFlags & CONV_FLAGS_RLE ) + if (convFlags & CONV_FLAGS_RLE) { - hr = _UncompressPixels( pPixels, remaining, image.GetImage(0,0,0), convFlags ); + hr = UncompressPixels(pPixels, remaining, image.GetImage(0, 0, 0), convFlags); } else { - hr = _CopyPixels( pPixels, remaining, image.GetImage(0,0,0), convFlags ); + hr = CopyPixels(pPixels, remaining, image.GetImage(0, 0, 0), convFlags); } - if ( FAILED(hr) ) + if (FAILED(hr)) { image.Release(); return hr; } - if ( metadata ) - memcpy( metadata, &mdata, sizeof(TexMetadata) ); + if (metadata) + memcpy(metadata, &mdata, sizeof(TexMetadata)); return S_OK; } @@ -962,49 +977,42 @@ HRESULT LoadFromTGAMemory( LPCVOID pSource, size_t size, TexMetadata* metadata, // Load a TGA file from disk //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT LoadFromTGAFile( LPCWSTR szFile, TexMetadata* metadata, ScratchImage& image ) +HRESULT DirectX::LoadFromTGAFile( + const wchar_t* szFile, + TexMetadata* metadata, + ScratchImage& image) { - if ( !szFile ) + if (!szFile) return E_INVALIDARG; image.Release(); #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) - ScopedHandle hFile( safe_handle( CreateFile2( szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, 0 ) ) ); + ScopedHandle hFile(safe_handle(CreateFile2(szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr))); #else - ScopedHandle hFile( safe_handle( CreateFileW( szFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, - FILE_FLAG_SEQUENTIAL_SCAN, 0 ) ) ); + ScopedHandle hFile(safe_handle(CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, nullptr))); #endif - if ( !hFile ) + if (!hFile) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } // Get the file size - LARGE_INTEGER fileSize = {0}; - -#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) FILE_STANDARD_INFO fileInfo; - if ( !GetFileInformationByHandleEx( hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo) ) ) + if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo))) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } - fileSize = fileInfo.EndOfFile; -#else - if ( !GetFileSizeEx( hFile.get(), &fileSize ) ) - { - return HRESULT_FROM_WIN32( GetLastError() ); - } -#endif // File is too big for 32-bit allocation, so reject read (4 GB should be plenty large enough for a valid TGA file) - if ( fileSize.HighPart > 0 ) + if (fileInfo.EndOfFile.HighPart > 0) { - return HRESULT_FROM_WIN32( ERROR_FILE_TOO_LARGE ); + return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE); } // Need at least enough data to fill the header to be a valid TGA - if ( fileSize.LowPart < sizeof(TGA_HEADER) ) + if (fileInfo.EndOfFile.LowPart < sizeof(TGA_HEADER)) { return E_FAIL; } @@ -1012,196 +1020,196 @@ HRESULT LoadFromTGAFile( LPCWSTR szFile, TexMetadata* metadata, ScratchImage& im // Read the header uint8_t header[sizeof(TGA_HEADER)]; DWORD bytesRead = 0; - if ( !ReadFile( hFile.get(), header, sizeof(TGA_HEADER), &bytesRead, 0 ) ) + if (!ReadFile(hFile.get(), header, sizeof(TGA_HEADER), &bytesRead, nullptr)) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } size_t offset; DWORD convFlags = 0; TexMetadata mdata; - HRESULT hr = _DecodeTGAHeader( header, bytesRead, mdata, offset, &convFlags ); - if ( FAILED(hr) ) + HRESULT hr = DecodeTGAHeader(header, bytesRead, mdata, offset, &convFlags); + if (FAILED(hr)) return hr; // Read the pixels - DWORD remaining = static_cast( fileSize.LowPart - offset ); - if ( remaining == 0 ) + DWORD remaining = static_cast(fileInfo.EndOfFile.LowPart - offset); + if (remaining == 0) return E_FAIL; - if ( offset > sizeof(TGA_HEADER) ) + if (offset > sizeof(TGA_HEADER)) { // Skip past the id string LARGE_INTEGER filePos = { static_cast(offset), 0 }; - if ( !SetFilePointerEx( hFile.get(), filePos, 0, FILE_BEGIN ) ) + if (!SetFilePointerEx(hFile.get(), filePos, 0, FILE_BEGIN)) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } } - hr = image.Initialize2D( mdata.format, mdata.width, mdata.height, 1, 1 ); - if ( FAILED(hr) ) + hr = image.Initialize2D(mdata.format, mdata.width, mdata.height, 1, 1); + if (FAILED(hr)) return hr; - assert( image.GetPixels() ); + assert(image.GetPixels()); - if ( !(convFlags & (CONV_FLAGS_RLE | CONV_FLAGS_EXPAND | CONV_FLAGS_INVERTX)) && (convFlags & CONV_FLAGS_INVERTY) ) + if (!(convFlags & (CONV_FLAGS_RLE | CONV_FLAGS_EXPAND | CONV_FLAGS_INVERTX)) && (convFlags & CONV_FLAGS_INVERTY)) { // This case we can read directly into the image buffer in place - if ( !ReadFile( hFile.get(), image.GetPixels(), static_cast( image.GetPixelsSize() ), &bytesRead, 0 ) ) + if (!ReadFile(hFile.get(), image.GetPixels(), static_cast(image.GetPixelsSize()), &bytesRead, nullptr)) { image.Release(); - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } - if ( bytesRead != image.GetPixelsSize() ) + if (bytesRead != image.GetPixelsSize()) { image.Release(); return E_FAIL; } - switch( mdata.format ) + switch (mdata.format) { case DXGI_FORMAT_R8G8B8A8_UNORM: + { + // TGA stores 32-bit data in BGRA form, need to swizzle to RGBA + assert(image.GetImageCount() == 1); + const Image* img = image.GetImage(0, 0, 0); + if (!img) + return E_POINTER; + + uint8_t *pPixels = img->pixels; + if (!pPixels) + return E_POINTER; + + size_t rowPitch = img->rowPitch; + + // Scan for non-zero alpha channel + bool nonzeroa = false; + + for (size_t h = 0; h < img->height; ++h) { - // TGA stores 32-bit data in BGRA form, need to swizzle to RGBA - assert( image.GetImageCount() == 1 ); - const Image* img = image.GetImage(0,0,0); - if ( !img ) - return E_POINTER; + const uint32_t* sPtr = reinterpret_cast(pPixels); - uint8_t *pPixels = img->pixels; - if ( !pPixels ) - return E_POINTER; - - size_t rowPitch = img->rowPitch; - - // Scan for non-zero alpha channel - bool nonzeroa = false; - - for( size_t h = 0; h < img->height; ++h ) + for (size_t x = 0; x < img->width; ++x) { - const uint32_t* sPtr = reinterpret_cast( pPixels ); - - for( size_t x=0; x < img->width; ++x ) + if ((*sPtr) & 0xff000000) { - if ( (*sPtr) & 0xff000000 ) - { - nonzeroa = true; - break; - } - - ++sPtr; + nonzeroa = true; + break; } - if ( nonzeroa ) - break; - - pPixels += rowPitch; + ++sPtr; } - DWORD tflags = ( !nonzeroa ) ? TEXP_SCANLINE_SETALPHA : TEXP_SCANLINE_NONE; + if (nonzeroa) + break; - // Swizzle scanlines - pPixels = img->pixels; - - for( size_t h = 0; h < img->height; ++h ) - { - _SwizzleScanline( pPixels, rowPitch, pPixels, rowPitch, mdata.format, tflags ); - pPixels += rowPitch; - } + pPixels += rowPitch; } - break; + + DWORD tflags = (!nonzeroa) ? TEXP_SCANLINE_SETALPHA : TEXP_SCANLINE_NONE; + + // Swizzle scanlines + pPixels = img->pixels; + + for (size_t h = 0; h < img->height; ++h) + { + _SwizzleScanline(pPixels, rowPitch, pPixels, rowPitch, mdata.format, tflags); + pPixels += rowPitch; + } + } + break; // If we start using DXGI_FORMAT_B8G8R8X8_UNORM or DXGI_FORMAT_B8G8R8A8_UNORM we need to check for a fully 0 alpha channel - + case DXGI_FORMAT_B5G5R5A1_UNORM: + { + assert(image.GetImageCount() == 1); + const Image* img = image.GetImage(0, 0, 0); + if (!img) + return E_POINTER; + + // Scan for non-zero alpha channel + bool nonzeroa = false; + + const uint8_t *pPixels = img->pixels; + if (!pPixels) + return E_POINTER; + + size_t rowPitch = img->rowPitch; + + for (size_t h = 0; h < img->height; ++h) { - assert( image.GetImageCount() == 1 ); - const Image* img = image.GetImage(0,0,0); - if ( !img ) - return E_POINTER; + const uint16_t* sPtr = reinterpret_cast(pPixels); - // Scan for non-zero alpha channel - bool nonzeroa = false; - - const uint8_t *pPixels = img->pixels; - if ( !pPixels ) - return E_POINTER; - - size_t rowPitch = img->rowPitch; - - for( size_t h = 0; h < img->height; ++h ) + for (size_t x = 0; x < img->width; ++x) { - const uint16_t* sPtr = reinterpret_cast( pPixels ); - - for( size_t x=0; x < img->width; ++x ) + if (*sPtr & 0x8000) { - if ( *sPtr & 0x8000 ) - { - nonzeroa = true; - break; - } - - ++sPtr; + nonzeroa = true; + break; } - if ( nonzeroa ) - break; - - pPixels += rowPitch; + ++sPtr; } - // If there are no non-zero alpha channel entries, we'll assume alpha is not used and force it to opaque - if ( !nonzeroa ) - { - hr = _SetAlphaChannelToOpaque( img ); - if ( FAILED(hr) ) - return hr; - } + if (nonzeroa) + break; + + pPixels += rowPitch; } - break; + + // If there are no non-zero alpha channel entries, we'll assume alpha is not used and force it to opaque + if (!nonzeroa) + { + hr = SetAlphaChannelToOpaque(img); + if (FAILED(hr)) + return hr; + } + } + break; } } else // RLE || EXPAND || INVERTX || !INVERTY { - std::unique_ptr temp( new (std::nothrow) uint8_t[ remaining ] ); - if ( !temp ) + std::unique_ptr temp(new (std::nothrow) uint8_t[remaining]); + if (!temp) { image.Release(); return E_OUTOFMEMORY; } - if ( !ReadFile( hFile.get(), temp.get(), remaining, &bytesRead, 0 ) ) + if (!ReadFile(hFile.get(), temp.get(), remaining, &bytesRead, nullptr)) { image.Release(); - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } - if ( bytesRead != remaining ) + if (bytesRead != remaining) { image.Release(); return E_FAIL; } - if ( convFlags & CONV_FLAGS_RLE ) + if (convFlags & CONV_FLAGS_RLE) { - hr = _UncompressPixels( temp.get(), remaining, image.GetImage(0,0,0), convFlags ); + hr = UncompressPixels(temp.get(), remaining, image.GetImage(0, 0, 0), convFlags); } else { - hr = _CopyPixels( temp.get(), remaining, image.GetImage(0,0,0), convFlags ); + hr = CopyPixels(temp.get(), remaining, image.GetImage(0, 0, 0), convFlags); } - if ( FAILED(hr) ) + if (FAILED(hr)) { image.Release(); return hr; } } - if ( metadata ) - memcpy( metadata, &mdata, sizeof(TexMetadata) ); + if (metadata) + memcpy(metadata, &mdata, sizeof(TexMetadata)); return S_OK; } @@ -1211,58 +1219,58 @@ HRESULT LoadFromTGAFile( LPCWSTR szFile, TexMetadata* metadata, ScratchImage& im // Save a TGA file to memory //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT SaveToTGAMemory( const Image& image, Blob& blob ) +HRESULT DirectX::SaveToTGAMemory(const Image& image, Blob& blob) { - if ( !image.pixels ) + if (!image.pixels) return E_POINTER; TGA_HEADER tga_header; DWORD convFlags = 0; - HRESULT hr = _EncodeTGAHeader( image, tga_header, convFlags ); - if ( FAILED(hr) ) + HRESULT hr = EncodeTGAHeader(image, tga_header, convFlags); + if (FAILED(hr)) return hr; blob.Release(); // Determine memory required for image data size_t rowPitch, slicePitch; - if ( convFlags & CONV_FLAGS_888 ) + if (convFlags & CONV_FLAGS_888) { rowPitch = image.width * 3; slicePitch = image.height * rowPitch; } else { - ComputePitch( image.format, image.width, image.height, rowPitch, slicePitch, CP_FLAGS_NONE ); + ComputePitch(image.format, image.width, image.height, rowPitch, slicePitch, CP_FLAGS_NONE); } - hr = blob.Initialize( sizeof(TGA_HEADER) + slicePitch ); - if ( FAILED(hr) ) + hr = blob.Initialize(sizeof(TGA_HEADER) + slicePitch); + if (FAILED(hr)) return hr; // Copy header - auto dPtr = reinterpret_cast( blob.GetBufferPointer() ); - assert( dPtr != 0 ); - memcpy_s( dPtr, blob.GetBufferSize(), &tga_header, sizeof(TGA_HEADER) ); + auto dPtr = reinterpret_cast(blob.GetBufferPointer()); + assert(dPtr != 0); + memcpy_s(dPtr, blob.GetBufferSize(), &tga_header, sizeof(TGA_HEADER)); dPtr += sizeof(TGA_HEADER); - auto pPixels = reinterpret_cast( image.pixels ); - assert( pPixels ); + auto pPixels = reinterpret_cast(image.pixels); + assert(pPixels); - for( size_t y = 0; y < image.height; ++y ) + for (size_t y = 0; y < image.height; ++y) { // Copy pixels - if ( convFlags & CONV_FLAGS_888 ) + if (convFlags & CONV_FLAGS_888) { - _Copy24bppScanline( dPtr, rowPitch, pPixels, image.rowPitch ); + Copy24bppScanline(dPtr, rowPitch, pPixels, image.rowPitch); } - else if ( convFlags & CONV_FLAGS_SWIZZLE ) + else if (convFlags & CONV_FLAGS_SWIZZLE) { - _SwizzleScanline( dPtr, rowPitch, pPixels, image.rowPitch, image.format, TEXP_SCANLINE_NONE ); + _SwizzleScanline(dPtr, rowPitch, pPixels, image.rowPitch, image.format, TEXP_SCANLINE_NONE); } else { - _CopyScanline( dPtr, rowPitch, pPixels, image.rowPitch, image.format, TEXP_SCANLINE_NONE ); + _CopyScanline(dPtr, rowPitch, pPixels, image.rowPitch, image.format, TEXP_SCANLINE_NONE); } dPtr += rowPitch; @@ -1277,62 +1285,61 @@ HRESULT SaveToTGAMemory( const Image& image, Blob& blob ) // Save a TGA file to disk //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT SaveToTGAFile( const Image& image, LPCWSTR szFile ) +HRESULT DirectX::SaveToTGAFile(const Image& image, const wchar_t* szFile) { - if ( !szFile ) + if (!szFile) return E_INVALIDARG; - if ( !image.pixels ) + if (!image.pixels) return E_POINTER; TGA_HEADER tga_header; DWORD convFlags = 0; - HRESULT hr = _EncodeTGAHeader( image, tga_header, convFlags ); - if ( FAILED(hr) ) + HRESULT hr = EncodeTGAHeader(image, tga_header, convFlags); + if (FAILED(hr)) return hr; // Create file and write header #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) - ScopedHandle hFile( safe_handle( CreateFile2( szFile, GENERIC_WRITE, 0, CREATE_ALWAYS, 0 ) ) ); + ScopedHandle hFile(safe_handle(CreateFile2(szFile, GENERIC_WRITE, 0, CREATE_ALWAYS, nullptr))); #else - ScopedHandle hFile( safe_handle( CreateFileW( szFile, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0 ) ) ); + ScopedHandle hFile(safe_handle(CreateFileW(szFile, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, nullptr))); #endif - if ( !hFile ) + if (!hFile) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } // Determine size for TGA pixel data size_t rowPitch, slicePitch; - if ( convFlags & CONV_FLAGS_888 ) + if (convFlags & CONV_FLAGS_888) { rowPitch = image.width * 3; slicePitch = image.height * rowPitch; } else { - ComputePitch( image.format, image.width, image.height, rowPitch, slicePitch, CP_FLAGS_NONE ); + ComputePitch(image.format, image.width, image.height, rowPitch, slicePitch, CP_FLAGS_NONE); } - if ( slicePitch < 65535 ) + if (slicePitch < 65535) { // For small images, it is better to create an in-memory file and write it out Blob blob; - hr = SaveToTGAMemory( image, blob ); - if ( FAILED(hr) ) + hr = SaveToTGAMemory(image, blob); + if (FAILED(hr)) return hr; // Write blob - const DWORD bytesToWrite = static_cast( blob.GetBufferSize() ); + const DWORD bytesToWrite = static_cast(blob.GetBufferSize()); DWORD bytesWritten; - if ( !WriteFile( hFile.get(), blob.GetBufferPointer(), bytesToWrite, - &bytesWritten, 0 ) ) + if (!WriteFile(hFile.get(), blob.GetBufferPointer(), bytesToWrite, &bytesWritten, nullptr)) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } - if ( bytesWritten != bytesToWrite ) + if (bytesWritten != bytesToWrite) { return E_FAIL; } @@ -1340,52 +1347,50 @@ HRESULT SaveToTGAFile( const Image& image, LPCWSTR szFile ) else { // Otherwise, write the image one scanline at a time... - std::unique_ptr temp( new (std::nothrow) uint8_t[ rowPitch ] ); - if ( !temp ) + std::unique_ptr temp(new (std::nothrow) uint8_t[rowPitch]); + if (!temp) return E_OUTOFMEMORY; // Write header DWORD bytesWritten; - if ( !WriteFile( hFile.get(), &tga_header, sizeof(TGA_HEADER), &bytesWritten, 0 ) ) + if (!WriteFile(hFile.get(), &tga_header, sizeof(TGA_HEADER), &bytesWritten, nullptr)) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } - if ( bytesWritten != sizeof(TGA_HEADER) ) + if (bytesWritten != sizeof(TGA_HEADER)) return E_FAIL; // Write pixels - auto pPixels = reinterpret_cast( image.pixels ); + auto pPixels = reinterpret_cast(image.pixels); - for( size_t y = 0; y < image.height; ++y ) + for (size_t y = 0; y < image.height; ++y) { // Copy pixels - if ( convFlags & CONV_FLAGS_888 ) + if (convFlags & CONV_FLAGS_888) { - _Copy24bppScanline( temp.get(), rowPitch, pPixels, image.rowPitch ); + Copy24bppScanline(temp.get(), rowPitch, pPixels, image.rowPitch); } - else if ( convFlags & CONV_FLAGS_SWIZZLE ) + else if (convFlags & CONV_FLAGS_SWIZZLE) { - _SwizzleScanline( temp.get(), rowPitch, pPixels, image.rowPitch, image.format, TEXP_SCANLINE_NONE ); + _SwizzleScanline(temp.get(), rowPitch, pPixels, image.rowPitch, image.format, TEXP_SCANLINE_NONE); } else { - _CopyScanline( temp.get(), rowPitch, pPixels, image.rowPitch, image.format, TEXP_SCANLINE_NONE ); + _CopyScanline(temp.get(), rowPitch, pPixels, image.rowPitch, image.format, TEXP_SCANLINE_NONE); } pPixels += image.rowPitch; - if ( !WriteFile( hFile.get(), temp.get(), static_cast( rowPitch ), &bytesWritten, 0 ) ) + if (!WriteFile(hFile.get(), temp.get(), static_cast(rowPitch), &bytesWritten, nullptr)) { - return HRESULT_FROM_WIN32( GetLastError() ); + return HRESULT_FROM_WIN32(GetLastError()); } - if ( bytesWritten != rowPitch ) + if (bytesWritten != rowPitch) return E_FAIL; } } return S_OK; } - -}; // namespace diff --git a/DirectXTex/DirectXTexUtil.cpp b/DirectXTex/DirectXTexUtil.cpp index d724971..afe29cc 100644 --- a/DirectXTex/DirectXTexUtil.cpp +++ b/DirectXTex/DirectXTexUtil.cpp @@ -15,8 +15,6 @@ #include "directxtexp.h" -using Microsoft::WRL::ComPtr; - #if defined(_XBOX_ONE) && defined(_TITLE) static_assert(XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT == DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT, "Xbox One XDK mismatch detected"); static_assert(XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT == DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT, "Xbox One XDK mismatch detected"); @@ -33,68 +31,70 @@ static_assert(WIN10_DXGI_FORMAT_V208 == DXGI_FORMAT_V208, "Windows SDK mismatch static_assert(WIN10_DXGI_FORMAT_V408 == DXGI_FORMAT_V408, "Windows SDK mismatch detected"); #endif +using namespace DirectX; +using Microsoft::WRL::ComPtr; -//------------------------------------------------------------------------------------- -// WIC Pixel Format Translation Data -//------------------------------------------------------------------------------------- -struct WICTranslate +namespace { - GUID wic; - DXGI_FORMAT format; - bool srgb; -}; + //------------------------------------------------------------------------------------- + // WIC Pixel Format Translation Data + //------------------------------------------------------------------------------------- + struct WICTranslate + { + GUID wic; + DXGI_FORMAT format; + bool srgb; + }; -static const WICTranslate g_WICFormats[] = -{ - { GUID_WICPixelFormat128bppRGBAFloat, DXGI_FORMAT_R32G32B32A32_FLOAT, false }, + const WICTranslate g_WICFormats[] = + { + { GUID_WICPixelFormat128bppRGBAFloat, DXGI_FORMAT_R32G32B32A32_FLOAT, false }, - { GUID_WICPixelFormat64bppRGBAHalf, DXGI_FORMAT_R16G16B16A16_FLOAT, false }, - { GUID_WICPixelFormat64bppRGBA, DXGI_FORMAT_R16G16B16A16_UNORM, true }, + { GUID_WICPixelFormat64bppRGBAHalf, DXGI_FORMAT_R16G16B16A16_FLOAT, false }, + { GUID_WICPixelFormat64bppRGBA, DXGI_FORMAT_R16G16B16A16_UNORM, true }, - { GUID_WICPixelFormat32bppRGBA, DXGI_FORMAT_R8G8B8A8_UNORM, true }, - { GUID_WICPixelFormat32bppBGRA, DXGI_FORMAT_B8G8R8A8_UNORM, true }, // DXGI 1.1 - { GUID_WICPixelFormat32bppBGR, DXGI_FORMAT_B8G8R8X8_UNORM, true }, // DXGI 1.1 + { GUID_WICPixelFormat32bppRGBA, DXGI_FORMAT_R8G8B8A8_UNORM, true }, + { GUID_WICPixelFormat32bppBGRA, DXGI_FORMAT_B8G8R8A8_UNORM, true }, // DXGI 1.1 + { GUID_WICPixelFormat32bppBGR, DXGI_FORMAT_B8G8R8X8_UNORM, true }, // DXGI 1.1 - { GUID_WICPixelFormat32bppRGBA1010102XR, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM, true }, // DXGI 1.1 - { GUID_WICPixelFormat32bppRGBA1010102, DXGI_FORMAT_R10G10B10A2_UNORM, true }, + { GUID_WICPixelFormat32bppRGBA1010102XR, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM, true }, // DXGI 1.1 + { GUID_WICPixelFormat32bppRGBA1010102, DXGI_FORMAT_R10G10B10A2_UNORM, true }, - { GUID_WICPixelFormat16bppBGRA5551, DXGI_FORMAT_B5G5R5A1_UNORM, true }, - { GUID_WICPixelFormat16bppBGR565, DXGI_FORMAT_B5G6R5_UNORM, true }, + { GUID_WICPixelFormat16bppBGRA5551, DXGI_FORMAT_B5G5R5A1_UNORM, true }, + { GUID_WICPixelFormat16bppBGR565, DXGI_FORMAT_B5G6R5_UNORM, true }, - { GUID_WICPixelFormat32bppGrayFloat, DXGI_FORMAT_R32_FLOAT, false }, - { GUID_WICPixelFormat16bppGrayHalf, DXGI_FORMAT_R16_FLOAT, false }, - { GUID_WICPixelFormat16bppGray, DXGI_FORMAT_R16_UNORM, true }, - { GUID_WICPixelFormat8bppGray, DXGI_FORMAT_R8_UNORM, true }, + { GUID_WICPixelFormat32bppGrayFloat, DXGI_FORMAT_R32_FLOAT, false }, + { GUID_WICPixelFormat16bppGrayHalf, DXGI_FORMAT_R16_FLOAT, false }, + { GUID_WICPixelFormat16bppGray, DXGI_FORMAT_R16_UNORM, true }, + { GUID_WICPixelFormat8bppGray, DXGI_FORMAT_R8_UNORM, true }, - { GUID_WICPixelFormat8bppAlpha, DXGI_FORMAT_A8_UNORM, false }, + { GUID_WICPixelFormat8bppAlpha, DXGI_FORMAT_A8_UNORM, false }, - { GUID_WICPixelFormatBlackWhite, DXGI_FORMAT_R1_UNORM, false }, -}; + { GUID_WICPixelFormatBlackWhite, DXGI_FORMAT_R1_UNORM, false }, + }; -static bool g_WIC2 = false; -static IWICImagingFactory* g_Factory = nullptr; + bool g_WIC2 = false; + IWICImagingFactory* g_Factory = nullptr; +} -namespace DirectX -{ - //===================================================================================== // WIC Utilities //===================================================================================== _Use_decl_annotations_ -DXGI_FORMAT _WICToDXGI( const GUID& guid ) +DXGI_FORMAT DirectX::_WICToDXGI(const GUID& guid) { - for( size_t i=0; i < _countof(g_WICFormats); ++i ) + for (size_t i = 0; i < _countof(g_WICFormats); ++i) { - if ( memcmp( &g_WICFormats[i].wic, &guid, sizeof(GUID) ) == 0 ) + if (memcmp(&g_WICFormats[i].wic, &guid, sizeof(GUID)) == 0) return g_WICFormats[i].format; } #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE) - if ( g_WIC2 ) + if (g_WIC2) { - if ( memcmp( &GUID_WICPixelFormat96bppRGBFloat, &guid, sizeof(GUID) ) == 0 ) + if (memcmp(&GUID_WICPixelFormat96bppRGBFloat, &guid, sizeof(GUID)) == 0) return DXGI_FORMAT_R32G32B32_FLOAT; } #endif @@ -103,7 +103,7 @@ DXGI_FORMAT _WICToDXGI( const GUID& guid ) } _Use_decl_annotations_ -bool _DXGIToWIC( DXGI_FORMAT format, GUID& guid, bool ignoreRGBvsBGR ) +bool DirectX::_DXGIToWIC( DXGI_FORMAT format, GUID& guid, bool ignoreRGBvsBGR ) { switch( format ) { @@ -163,28 +163,28 @@ bool _DXGIToWIC( DXGI_FORMAT format, GUID& guid, bool ignoreRGBvsBGR ) return false; } -DWORD _CheckWICColorSpace( _In_ const GUID& sourceGUID, _In_ const GUID& targetGUID ) +DWORD DirectX::_CheckWICColorSpace(_In_ const GUID& sourceGUID, _In_ const GUID& targetGUID) { DWORD srgb = 0; - for( size_t i=0; i < _countof(g_WICFormats); ++i ) + for (size_t i = 0; i < _countof(g_WICFormats); ++i) { - if ( memcmp( &g_WICFormats[i].wic, &sourceGUID, sizeof(GUID) ) == 0 ) + if (memcmp(&g_WICFormats[i].wic, &sourceGUID, sizeof(GUID)) == 0) { - if ( g_WICFormats[i].srgb ) + if (g_WICFormats[i].srgb) srgb |= TEX_FILTER_SRGB_IN; } - if ( memcmp( &g_WICFormats[i].wic, &targetGUID, sizeof(GUID) ) == 0 ) + if (memcmp(&g_WICFormats[i].wic, &targetGUID, sizeof(GUID)) == 0) { - if ( g_WICFormats[i].srgb ) + if (g_WICFormats[i].srgb) srgb |= TEX_FILTER_SRGB_OUT; } } - if ( (srgb & (TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT)) == (TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT) ) + if ((srgb & (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT)) == (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT)) { - srgb &= ~(TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT); + srgb &= ~(TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT); } return srgb; @@ -195,9 +195,9 @@ DWORD _CheckWICColorSpace( _In_ const GUID& sourceGUID, _In_ const GUID& targetG // Public helper function to get common WIC codec GUIDs //------------------------------------------------------------------------------------- _Use_decl_annotations_ -REFGUID GetWICCodec( WICCodecs codec ) +REFGUID DirectX::GetWICCodec(WICCodecs codec) { - switch( codec ) + switch (codec) { case WIC_CODEC_BMP: return GUID_ContainerFormatBmp; @@ -229,9 +229,9 @@ REFGUID GetWICCodec( WICCodecs codec ) //------------------------------------------------------------------------------------- // Singleton function for WIC factory //------------------------------------------------------------------------------------- -IWICImagingFactory* GetWICFactory( bool& iswic2 ) +IWICImagingFactory* DirectX::GetWICFactory(bool& iswic2) { - if ( g_Factory ) + if (g_Factory) { iswic2 = g_WIC2; return g_Factory; @@ -240,47 +240,47 @@ IWICImagingFactory* GetWICFactory( bool& iswic2 ) static INIT_ONCE s_initOnce = INIT_ONCE_STATIC_INIT; InitOnceExecuteOnce(&s_initOnce, - [](PINIT_ONCE, PVOID, PVOID *factory) -> BOOL + [](PINIT_ONCE, PVOID, LPVOID *factory) -> BOOL + { +#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE) + HRESULT hr = CoCreateInstance( + CLSID_WICImagingFactory2, + nullptr, + CLSCTX_INPROC_SERVER, + __uuidof(IWICImagingFactory2), + factory + ); + + if (SUCCEEDED(hr)) + { + // WIC2 is available on Windows 10, Windows 8.x, and Windows 7 SP1 with KB 2670838 installed + g_WIC2 = true; + return TRUE; + } + else { - #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE) - HRESULT hr = CoCreateInstance( - CLSID_WICImagingFactory2, - nullptr, - CLSCTX_INPROC_SERVER, - __uuidof(IWICImagingFactory2), - factory - ); - - if (SUCCEEDED(hr)) - { - // WIC2 is available on Windows 10, Windows 8.x, and Windows 7 SP1 with KB 2670838 installed - g_WIC2 = true; - return TRUE; - } - else - { - g_WIC2 = false; - - hr = CoCreateInstance( - CLSID_WICImagingFactory1, - nullptr, - CLSCTX_INPROC_SERVER, - __uuidof(IWICImagingFactory), - factory - ); - return SUCCEEDED(hr) ? TRUE : FALSE; - } - #else g_WIC2 = false; - return SUCCEEDED( CoCreateInstance( - CLSID_WICImagingFactory, + hr = CoCreateInstance( + CLSID_WICImagingFactory1, nullptr, CLSCTX_INPROC_SERVER, __uuidof(IWICImagingFactory), - factory) ) ? TRUE : FALSE; - #endif - }, nullptr, reinterpret_cast(&g_Factory) ); + factory + ); + return SUCCEEDED(hr) ? TRUE : FALSE; + } +#else + g_WIC2 = false; + + return SUCCEEDED(CoCreateInstance( + CLSID_WICImagingFactory, + nullptr, + CLSCTX_INPROC_SERVER, + __uuidof(IWICImagingFactory), + factory)) ? TRUE : FALSE; +#endif + }, nullptr, reinterpret_cast(&g_Factory)); iswic2 = g_WIC2; return g_Factory; @@ -290,7 +290,7 @@ IWICImagingFactory* GetWICFactory( bool& iswic2 ) //------------------------------------------------------------------------------------- // Optional initializer for WIC factory //------------------------------------------------------------------------------------- -void SetWICFactory(_In_opt_ IWICImagingFactory* pWIC) +void DirectX::SetWICFactory(_In_opt_ IWICImagingFactory* pWIC) { if (pWIC == g_Factory) return; @@ -311,7 +311,7 @@ void SetWICFactory(_In_opt_ IWICImagingFactory* pWIC) g_WIC2 = iswic2; std::swap(pWIC, g_Factory); - if ( pWIC ) + if (pWIC) pWIC->Release(); } @@ -323,9 +323,9 @@ void SetWICFactory(_In_opt_ IWICImagingFactory* pWIC) //------------------------------------------------------------------------------------- _Use_decl_annotations_ -bool IsPacked(DXGI_FORMAT fmt) +bool DirectX::IsPacked(DXGI_FORMAT fmt) { - switch( static_cast(fmt) ) + switch (static_cast(fmt)) { case DXGI_FORMAT_R8G8_B8G8_UNORM: case DXGI_FORMAT_G8R8_G8B8_UNORM: @@ -342,9 +342,9 @@ bool IsPacked(DXGI_FORMAT fmt) //------------------------------------------------------------------------------------- _Use_decl_annotations_ -bool IsVideo(DXGI_FORMAT fmt) +bool DirectX::IsVideo(DXGI_FORMAT fmt) { - switch ( static_cast(fmt) ) + switch (static_cast(fmt)) { case DXGI_FORMAT_AYUV: case DXGI_FORMAT_Y410: @@ -379,9 +379,9 @@ bool IsVideo(DXGI_FORMAT fmt) //------------------------------------------------------------------------------------- _Use_decl_annotations_ -bool IsPlanar(DXGI_FORMAT fmt) +bool DirectX::IsPlanar(DXGI_FORMAT fmt) { - switch ( static_cast(fmt) ) + switch (static_cast(fmt)) { case DXGI_FORMAT_NV12: // 4:2:0 8-bit case DXGI_FORMAT_P010: // 4:2:0 10-bit @@ -403,15 +403,14 @@ bool IsPlanar(DXGI_FORMAT fmt) default: return false; } - } //------------------------------------------------------------------------------------- _Use_decl_annotations_ -bool IsDepthStencil(DXGI_FORMAT fmt) +bool DirectX::IsDepthStencil(DXGI_FORMAT fmt) { - switch( static_cast(fmt) ) + switch (static_cast(fmt)) { case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: @@ -434,9 +433,9 @@ bool IsDepthStencil(DXGI_FORMAT fmt) //------------------------------------------------------------------------------------- _Use_decl_annotations_ -bool IsTypeless(DXGI_FORMAT fmt, bool partialTypeless) +bool DirectX::IsTypeless(DXGI_FORMAT fmt, bool partialTypeless) { - switch( static_cast(fmt) ) + switch (static_cast(fmt)) { case DXGI_FORMAT_R32G32B32A32_TYPELESS: case DXGI_FORMAT_R32G32B32_TYPELESS: @@ -478,9 +477,9 @@ bool IsTypeless(DXGI_FORMAT fmt, bool partialTypeless) //------------------------------------------------------------------------------------- _Use_decl_annotations_ -bool HasAlpha(DXGI_FORMAT fmt) +bool DirectX::HasAlpha(DXGI_FORMAT fmt) { - switch( static_cast(fmt) ) + switch (static_cast(fmt)) { case DXGI_FORMAT_R32G32B32A32_TYPELESS: case DXGI_FORMAT_R32G32B32A32_FLOAT: @@ -541,9 +540,9 @@ bool HasAlpha(DXGI_FORMAT fmt) // Returns bits-per-pixel for a given DXGI format, or 0 on failure //------------------------------------------------------------------------------------- _Use_decl_annotations_ -size_t BitsPerPixel( DXGI_FORMAT fmt ) +size_t DirectX::BitsPerPixel(DXGI_FORMAT fmt) { - switch( static_cast(fmt) ) + switch (static_cast(fmt)) { case DXGI_FORMAT_R32G32B32A32_TYPELESS: case DXGI_FORMAT_R32G32B32A32_FLOAT: @@ -703,9 +702,9 @@ size_t BitsPerPixel( DXGI_FORMAT fmt ) // For mixed formats, it returns the largest color-depth in the format //------------------------------------------------------------------------------------- _Use_decl_annotations_ -size_t BitsPerColor( DXGI_FORMAT fmt ) +size_t DirectX::BitsPerColor(DXGI_FORMAT fmt) { - switch( static_cast(fmt) ) + switch (static_cast(fmt)) { case DXGI_FORMAT_R32G32B32A32_TYPELESS: case DXGI_FORMAT_R32G32B32A32_FLOAT: @@ -869,10 +868,10 @@ size_t BitsPerColor( DXGI_FORMAT fmt ) // based on DXGI format, width, and height //------------------------------------------------------------------------------------- _Use_decl_annotations_ -void ComputePitch( DXGI_FORMAT fmt, size_t width, size_t height, - size_t& rowPitch, size_t& slicePitch, DWORD flags ) +void DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height, + size_t& rowPitch, size_t& slicePitch, DWORD flags) { - switch( static_cast(fmt) ) + switch (static_cast(fmt)) { case DXGI_FORMAT_BC1_TYPELESS: case DXGI_FORMAT_BC1_UNORM: @@ -882,8 +881,8 @@ void ComputePitch( DXGI_FORMAT fmt, size_t width, size_t height, case DXGI_FORMAT_BC4_SNORM: assert(IsCompressed(fmt)); { - size_t nbw = std::max( 1, (width + 3) / 4 ); - size_t nbh = std::max( 1, (height + 3) / 4 ); + size_t nbw = std::max(1, (width + 3) / 4); + size_t nbh = std::max(1, (height + 3) / 4); rowPitch = nbw * 8; slicePitch = rowPitch * nbh; @@ -907,8 +906,8 @@ void ComputePitch( DXGI_FORMAT fmt, size_t width, size_t height, case DXGI_FORMAT_BC7_UNORM_SRGB: assert(IsCompressed(fmt)); { - size_t nbw = std::max( 1, (width + 3) / 4 ); - size_t nbh = std::max( 1, (height + 3) / 4 ); + size_t nbw = std::max(1, (width + 3) / 4); + size_t nbh = std::max(1, (height + 3) / 4); rowPitch = nbw * 16; slicePitch = rowPitch * nbh; @@ -919,22 +918,22 @@ void ComputePitch( DXGI_FORMAT fmt, size_t width, size_t height, case DXGI_FORMAT_G8R8_G8B8_UNORM: case DXGI_FORMAT_YUY2: assert(IsPacked(fmt)); - rowPitch = ( ( width + 1 ) >> 1 ) * 4; + rowPitch = ((width + 1) >> 1) * 4; slicePitch = rowPitch * height; break; case DXGI_FORMAT_Y210: case DXGI_FORMAT_Y216: assert(IsPacked(fmt)); - rowPitch = ( ( width + 1 ) >> 1 ) * 8; + rowPitch = ((width + 1) >> 1) * 8; slicePitch = rowPitch * height; break; case DXGI_FORMAT_NV12: case DXGI_FORMAT_420_OPAQUE: assert(IsPlanar(fmt)); - rowPitch = ( ( width + 1 ) >> 1 ) * 2; - slicePitch = rowPitch * ( height + ( ( height + 1 ) >> 1 ) ); + rowPitch = ((width + 1) >> 1) * 2; + slicePitch = rowPitch * (height + ((height + 1) >> 1)); break; case DXGI_FORMAT_P010: @@ -943,84 +942,84 @@ void ComputePitch( DXGI_FORMAT fmt, size_t width, size_t height, case XBOX_DXGI_FORMAT_R16_UNORM_X8_TYPELESS: case XBOX_DXGI_FORMAT_X16_TYPELESS_G8_UINT: assert(IsPlanar(fmt)); - rowPitch = ( ( width + 1 ) >> 1 ) * 4; - slicePitch = rowPitch * ( height + ( ( height + 1 ) >> 1 ) ); + rowPitch = ((width + 1) >> 1) * 4; + slicePitch = rowPitch * (height + ((height + 1) >> 1)); break; case DXGI_FORMAT_NV11: assert(IsPlanar(fmt)); - rowPitch = ( ( width + 3 ) >> 2 ) * 4; + rowPitch = ((width + 3) >> 2) * 4; slicePitch = rowPitch * height * 2; break; case WIN10_DXGI_FORMAT_P208: assert(IsPlanar(fmt)); - rowPitch = ( ( width + 1 ) >> 1 ) * 2; + rowPitch = ((width + 1) >> 1) * 2; slicePitch = rowPitch * height * 2; break; case WIN10_DXGI_FORMAT_V208: assert(IsPlanar(fmt)); rowPitch = width; - slicePitch = rowPitch * ( height + ( ( ( height + 1 ) >> 1 ) * 2 ) ); + slicePitch = rowPitch * (height + (((height + 1) >> 1) * 2)); break; case WIN10_DXGI_FORMAT_V408: assert(IsPlanar(fmt)); rowPitch = width; - slicePitch = rowPitch * ( height + ( ( height >> 1 ) * 4 ) ); + slicePitch = rowPitch * (height + ((height >> 1) * 4)); break; default: - assert( IsValid(fmt) ); - assert( !IsCompressed(fmt) && !IsPacked(fmt) && !IsPlanar(fmt) ); + assert(IsValid(fmt)); + assert(!IsCompressed(fmt) && !IsPacked(fmt) && !IsPlanar(fmt)); { size_t bpp; - if ( flags & CP_FLAGS_24BPP ) + if (flags & CP_FLAGS_24BPP) bpp = 24; - else if ( flags & CP_FLAGS_16BPP ) + else if (flags & CP_FLAGS_16BPP) bpp = 16; - else if ( flags & CP_FLAGS_8BPP ) + else if (flags & CP_FLAGS_8BPP) bpp = 8; else - bpp = BitsPerPixel( fmt ); + bpp = BitsPerPixel(fmt); - if ( flags & ( CP_FLAGS_LEGACY_DWORD | CP_FLAGS_PARAGRAPH | CP_FLAGS_YMM | CP_FLAGS_ZMM | CP_FLAGS_PAGE4K ) ) + if (flags & (CP_FLAGS_LEGACY_DWORD | CP_FLAGS_PARAGRAPH | CP_FLAGS_YMM | CP_FLAGS_ZMM | CP_FLAGS_PAGE4K)) { - if ( flags & CP_FLAGS_PAGE4K ) + if (flags & CP_FLAGS_PAGE4K) { - rowPitch = ( ( width * bpp + 32767 ) / 32768 ) * 4096; + rowPitch = ((width * bpp + 32767) / 32768) * 4096; slicePitch = rowPitch * height; } - else if ( flags & CP_FLAGS_ZMM ) + else if (flags & CP_FLAGS_ZMM) { - rowPitch = ( ( width * bpp + 511 ) / 512 ) * 64; + rowPitch = ((width * bpp + 511) / 512) * 64; slicePitch = rowPitch * height; } - else if ( flags & CP_FLAGS_YMM ) + else if (flags & CP_FLAGS_YMM) { - rowPitch = ( ( width * bpp + 255 ) / 256) * 32; + rowPitch = ((width * bpp + 255) / 256) * 32; slicePitch = rowPitch * height; } - else if ( flags & CP_FLAGS_PARAGRAPH ) + else if (flags & CP_FLAGS_PARAGRAPH) { - rowPitch = ( ( width * bpp + 127 ) / 128 ) * 16; + rowPitch = ((width * bpp + 127) / 128) * 16; slicePitch = rowPitch * height; } else // DWORD alignment { // Special computation for some incorrectly created DDS files based on // legacy DirectDraw assumptions about pitch alignment - rowPitch = ( ( width * bpp + 31 ) / 32 ) * sizeof(uint32_t); + rowPitch = ((width * bpp + 31) / 32) * sizeof(uint32_t); slicePitch = rowPitch * height; } } else { // Default byte alignment - rowPitch = ( width * bpp + 7 ) / 8; + rowPitch = (width * bpp + 7) / 8; slicePitch = rowPitch * height; } } @@ -1031,9 +1030,9 @@ void ComputePitch( DXGI_FORMAT fmt, size_t width, size_t height, //------------------------------------------------------------------------------------- _Use_decl_annotations_ -size_t ComputeScanlines(DXGI_FORMAT fmt, size_t height) +size_t DirectX::ComputeScanlines(DXGI_FORMAT fmt, size_t height) { - switch ( static_cast(fmt) ) + switch (static_cast(fmt)) { case DXGI_FORMAT_BC1_TYPELESS: case DXGI_FORMAT_BC1_UNORM: @@ -1057,7 +1056,7 @@ size_t ComputeScanlines(DXGI_FORMAT fmt, size_t height) case DXGI_FORMAT_BC7_UNORM: case DXGI_FORMAT_BC7_UNORM_SRGB: assert(IsCompressed(fmt)); - return std::max( 1, (height + 3) / 4 ); + return std::max(1, (height + 3) / 4); case DXGI_FORMAT_NV11: case WIN10_DXGI_FORMAT_P208: @@ -1066,11 +1065,11 @@ size_t ComputeScanlines(DXGI_FORMAT fmt, size_t height) case WIN10_DXGI_FORMAT_V208: assert(IsPlanar(fmt)); - return height + ( ( (height + 1) >> 1 ) * 2 ); + return height + (((height + 1) >> 1) * 2); case WIN10_DXGI_FORMAT_V408: assert(IsPlanar(fmt)); - return height + ( (height >> 1) * 4 ); + return height + ((height >> 1) * 4); case DXGI_FORMAT_NV12: case DXGI_FORMAT_P010: @@ -1080,11 +1079,11 @@ size_t ComputeScanlines(DXGI_FORMAT fmt, size_t height) case XBOX_DXGI_FORMAT_R16_UNORM_X8_TYPELESS: case XBOX_DXGI_FORMAT_X16_TYPELESS_G8_UINT: assert(IsPlanar(fmt)); - return height + ( ( height + 1 ) >> 1 ); + return height + ((height + 1) >> 1); default: - assert( IsValid(fmt) ); - assert( !IsCompressed(fmt) && !IsPlanar(fmt) ); + assert(IsValid(fmt)); + assert(!IsCompressed(fmt) && !IsPlanar(fmt)); return height; } } @@ -1094,9 +1093,9 @@ size_t ComputeScanlines(DXGI_FORMAT fmt, size_t height) // Converts to an SRGB equivalent type if available //------------------------------------------------------------------------------------- _Use_decl_annotations_ -DXGI_FORMAT MakeSRGB( DXGI_FORMAT fmt ) +DXGI_FORMAT DirectX::MakeSRGB(DXGI_FORMAT fmt) { - switch( fmt ) + switch (fmt) { case DXGI_FORMAT_R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; @@ -1129,9 +1128,9 @@ DXGI_FORMAT MakeSRGB( DXGI_FORMAT fmt ) // Converts to a format to an equivalent TYPELESS format if available //------------------------------------------------------------------------------------- _Use_decl_annotations_ -DXGI_FORMAT MakeTypeless( DXGI_FORMAT fmt ) +DXGI_FORMAT DirectX::MakeTypeless(DXGI_FORMAT fmt) { - switch( static_cast( fmt ) ) + switch (static_cast(fmt)) { case DXGI_FORMAT_R32G32B32A32_FLOAT: case DXGI_FORMAT_R32G32B32A32_UINT: @@ -1249,9 +1248,9 @@ DXGI_FORMAT MakeTypeless( DXGI_FORMAT fmt ) // Converts to a TYPELESS format to an equivalent UNORM format if available //------------------------------------------------------------------------------------- _Use_decl_annotations_ -DXGI_FORMAT MakeTypelessUNORM( DXGI_FORMAT fmt ) +DXGI_FORMAT DirectX::MakeTypelessUNORM(DXGI_FORMAT fmt) { - switch( fmt ) + switch (fmt) { case DXGI_FORMAT_R16G16B16A16_TYPELESS: return DXGI_FORMAT_R16G16B16A16_UNORM; @@ -1308,9 +1307,9 @@ DXGI_FORMAT MakeTypelessUNORM( DXGI_FORMAT fmt ) // Converts to a TYPELESS format to an equivalent FLOAT format if available //------------------------------------------------------------------------------------- _Use_decl_annotations_ -DXGI_FORMAT MakeTypelessFLOAT( DXGI_FORMAT fmt ) +DXGI_FORMAT DirectX::MakeTypelessFLOAT(DXGI_FORMAT fmt) { - switch( fmt ) + switch (fmt) { case DXGI_FORMAT_R32G32B32A32_TYPELESS: return DXGI_FORMAT_R32G32B32A32_FLOAT; @@ -1344,25 +1343,25 @@ DXGI_FORMAT MakeTypelessFLOAT( DXGI_FORMAT fmt ) //===================================================================================== _Use_decl_annotations_ -size_t TexMetadata::ComputeIndex( size_t mip, size_t item, size_t slice ) const +size_t TexMetadata::ComputeIndex(size_t mip, size_t item, size_t slice) const { - if ( mip >= mipLevels ) + if (mip >= mipLevels) return size_t(-1); - switch( dimension ) + switch (dimension) { case TEX_DIMENSION_TEXTURE1D: case TEX_DIMENSION_TEXTURE2D: - if ( slice > 0 ) + if (slice > 0) return size_t(-1); - if ( item >= arraySize ) + if (item >= arraySize) return size_t(-1); - return (item*( mipLevels ) + mip); + return (item*(mipLevels)+mip); case TEX_DIMENSION_TEXTURE3D: - if ( item > 0 ) + if (item > 0) { // No support for arrays of volumes return size_t(-1); @@ -1372,14 +1371,14 @@ size_t TexMetadata::ComputeIndex( size_t mip, size_t item, size_t slice ) const size_t index = 0; size_t d = depth; - for( size_t level = 0; level < mip; ++level ) + for (size_t level = 0; level < mip; ++level) { index += d; - if ( d > 1 ) + if (d > 1) d >>= 1; } - if ( slice >= d ) + if (slice >= d) return size_t(-1); index += slice; @@ -1400,48 +1399,46 @@ size_t TexMetadata::ComputeIndex( size_t mip, size_t item, size_t slice ) const Blob& Blob::operator= (Blob&& moveFrom) { - if ( this != &moveFrom ) + if (this != &moveFrom) { Release(); - _buffer = moveFrom._buffer; - _size = moveFrom._size; + m_buffer = moveFrom.m_buffer; + m_size = moveFrom.m_size; - moveFrom._buffer = nullptr; - moveFrom._size = 0; + moveFrom.m_buffer = nullptr; + moveFrom.m_size = 0; } return *this; } void Blob::Release() { - if ( _buffer ) + if (m_buffer) { - _aligned_free( _buffer ); - _buffer = nullptr; + _aligned_free(m_buffer); + m_buffer = nullptr; } - _size = 0; + m_size = 0; } _Use_decl_annotations_ -HRESULT Blob::Initialize( size_t size ) +HRESULT Blob::Initialize(size_t size) { - if ( !size ) + if (!size) return E_INVALIDARG; Release(); - _buffer = _aligned_malloc( size, 16 ); - if ( !_buffer ) + m_buffer = _aligned_malloc(size, 16); + if (!m_buffer) { Release(); return E_OUTOFMEMORY; } - _size = size; + m_size = size; return S_OK; } - -}; // namespace diff --git a/DirectXTex/DirectXTexWIC.cpp b/DirectXTex/DirectXTexWIC.cpp index dee8c64..26da431 100644 --- a/DirectXTex/DirectXTexWIC.cpp +++ b/DirectXTex/DirectXTexWIC.cpp @@ -15,8 +15,6 @@ #include "directxtexp.h" -using Microsoft::WRL::ComPtr; - //------------------------------------------------------------------------------------- // IStream support for WIC Memory routines //------------------------------------------------------------------------------------- @@ -66,784 +64,818 @@ using Microsoft::WRL::ComPtr; #endif +using namespace DirectX; +using Microsoft::WRL::ComPtr; -//------------------------------------------------------------------------------------- -// WIC Pixel Format nearest conversion table -//------------------------------------------------------------------------------------- - -struct WICConvert -{ - GUID source; - GUID target; -}; - -static const WICConvert g_WICConvert[] = -{ - // Directly support the formats listed in XnaTexUtil::g_WICFormats, so no conversion required - // Note target GUID in this conversion table must be one of those directly supported formats. - - { GUID_WICPixelFormat1bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM - { GUID_WICPixelFormat2bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM - { GUID_WICPixelFormat4bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM - { GUID_WICPixelFormat8bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM - - { GUID_WICPixelFormat2bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM - { GUID_WICPixelFormat4bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM - - { GUID_WICPixelFormat16bppGrayFixedPoint, GUID_WICPixelFormat16bppGrayHalf }, // DXGI_FORMAT_R16_FLOAT - { GUID_WICPixelFormat32bppGrayFixedPoint, GUID_WICPixelFormat32bppGrayFloat }, // DXGI_FORMAT_R32_FLOAT - - { GUID_WICPixelFormat16bppBGR555, GUID_WICPixelFormat16bppBGRA5551 }, // DXGI_FORMAT_B5G5R5A1_UNORM - { GUID_WICPixelFormat32bppBGR101010, GUID_WICPixelFormat32bppRGBA1010102 }, // DXGI_FORMAT_R10G10B10A2_UNORM - - { GUID_WICPixelFormat24bppBGR, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM - { GUID_WICPixelFormat24bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM - { GUID_WICPixelFormat32bppPBGRA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM - { GUID_WICPixelFormat32bppPRGBA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM - - { GUID_WICPixelFormat48bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM - { GUID_WICPixelFormat48bppBGR, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM - { GUID_WICPixelFormat64bppBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM - { GUID_WICPixelFormat64bppPRGBA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM - { GUID_WICPixelFormat64bppPBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM - - { GUID_WICPixelFormat48bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT - { GUID_WICPixelFormat48bppBGRFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT - { GUID_WICPixelFormat64bppRGBAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT - { GUID_WICPixelFormat64bppBGRAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT - { GUID_WICPixelFormat64bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT - { GUID_WICPixelFormat64bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT - { GUID_WICPixelFormat48bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT - - { GUID_WICPixelFormat128bppPRGBAFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT - { GUID_WICPixelFormat128bppRGBFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT - { GUID_WICPixelFormat128bppRGBAFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT - { GUID_WICPixelFormat128bppRGBFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT - { GUID_WICPixelFormat32bppRGBE, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT - - { GUID_WICPixelFormat32bppCMYK, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM - { GUID_WICPixelFormat64bppCMYK, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM - { GUID_WICPixelFormat40bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM - { GUID_WICPixelFormat80bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM - -#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE) - { GUID_WICPixelFormat32bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM - { GUID_WICPixelFormat64bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM - { GUID_WICPixelFormat64bppPRGBAHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT -#endif - - // We don't support n-channel formats -}; - -namespace DirectX +namespace { -//------------------------------------------------------------------------------------- -// Returns the DXGI format and optionally the WIC pixel GUID to convert to -//------------------------------------------------------------------------------------- -static DXGI_FORMAT _DetermineFormat( _In_ const WICPixelFormatGUID& pixelFormat, _In_ DWORD flags, _In_ bool iswic2, - _Out_opt_ WICPixelFormatGUID* pConvert ) -{ - if ( pConvert ) - memset( pConvert, 0, sizeof(WICPixelFormatGUID) ); + //------------------------------------------------------------------------------------- + // WIC Pixel Format nearest conversion table + //------------------------------------------------------------------------------------- - DXGI_FORMAT format = _WICToDXGI( pixelFormat ); - - if ( format == DXGI_FORMAT_UNKNOWN ) + struct WICConvert { - if ( memcmp( &GUID_WICPixelFormat96bppRGBFixedPoint, &pixelFormat, sizeof(WICPixelFormatGUID) ) == 0 ) + GUID source; + GUID target; + }; + + const WICConvert g_WICConvert[] = + { + // Directly support the formats listed in XnaTexUtil::g_WICFormats, so no conversion required + // Note target GUID in this conversion table must be one of those directly supported formats. + + { GUID_WICPixelFormat1bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat2bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat4bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat8bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + + { GUID_WICPixelFormat2bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM + { GUID_WICPixelFormat4bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM + + { GUID_WICPixelFormat16bppGrayFixedPoint, GUID_WICPixelFormat16bppGrayHalf }, // DXGI_FORMAT_R16_FLOAT + { GUID_WICPixelFormat32bppGrayFixedPoint, GUID_WICPixelFormat32bppGrayFloat }, // DXGI_FORMAT_R32_FLOAT + + { GUID_WICPixelFormat16bppBGR555, GUID_WICPixelFormat16bppBGRA5551 }, // DXGI_FORMAT_B5G5R5A1_UNORM + { GUID_WICPixelFormat32bppBGR101010, GUID_WICPixelFormat32bppRGBA1010102 }, // DXGI_FORMAT_R10G10B10A2_UNORM + + { GUID_WICPixelFormat24bppBGR, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat24bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat32bppPBGRA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat32bppPRGBA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + + { GUID_WICPixelFormat48bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat48bppBGR, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat64bppBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat64bppPRGBA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat64bppPBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + + { GUID_WICPixelFormat48bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat48bppBGRFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat64bppRGBAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat64bppBGRAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat64bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat64bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat48bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + + { GUID_WICPixelFormat128bppPRGBAFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + { GUID_WICPixelFormat128bppRGBFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + { GUID_WICPixelFormat128bppRGBAFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + { GUID_WICPixelFormat128bppRGBFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + { GUID_WICPixelFormat32bppRGBE, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + + { GUID_WICPixelFormat32bppCMYK, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat64bppCMYK, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat40bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat80bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + + #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE) + { GUID_WICPixelFormat32bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat64bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat64bppPRGBAHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + #endif + + // We don't support n-channel formats + }; + + //------------------------------------------------------------------------------------- + // Returns the DXGI format and optionally the WIC pixel GUID to convert to + //------------------------------------------------------------------------------------- + DXGI_FORMAT DetermineFormat( + _In_ const WICPixelFormatGUID& pixelFormat, + DWORD flags, + bool iswic2, + _Out_opt_ WICPixelFormatGUID* pConvert) + { + if (pConvert) + memset(pConvert, 0, sizeof(WICPixelFormatGUID)); + + DXGI_FORMAT format = _WICToDXGI(pixelFormat); + + if (format == DXGI_FORMAT_UNKNOWN) { -#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE) - if ( iswic2 ) + if (memcmp(&GUID_WICPixelFormat96bppRGBFixedPoint, &pixelFormat, sizeof(WICPixelFormatGUID)) == 0) { - if ( pConvert ) - memcpy( pConvert, &GUID_WICPixelFormat96bppRGBFloat, sizeof(WICPixelFormatGUID) ); - format = DXGI_FORMAT_R32G32B32_FLOAT; +#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE) + if (iswic2) + { + if (pConvert) + memcpy(pConvert, &GUID_WICPixelFormat96bppRGBFloat, sizeof(WICPixelFormatGUID)); + format = DXGI_FORMAT_R32G32B32_FLOAT; + } + else +#else + UNREFERENCED_PARAMETER(iswic2); +#endif + { + if (pConvert) + memcpy(pConvert, &GUID_WICPixelFormat128bppRGBAFloat, sizeof(WICPixelFormatGUID)); + format = DXGI_FORMAT_R32G32B32A32_FLOAT; + } } else -#else - UNREFERENCED_PARAMETER(iswic2); -#endif { - if ( pConvert ) - memcpy( pConvert, &GUID_WICPixelFormat128bppRGBAFloat, sizeof(WICPixelFormatGUID) ); - format = DXGI_FORMAT_R32G32B32A32_FLOAT; + for (size_t i = 0; i < _countof(g_WICConvert); ++i) + { + if (memcmp(&g_WICConvert[i].source, &pixelFormat, sizeof(WICPixelFormatGUID)) == 0) + { + if (pConvert) + memcpy(pConvert, &g_WICConvert[i].target, sizeof(WICPixelFormatGUID)); + + format = _WICToDXGI(g_WICConvert[i].target); + assert(format != DXGI_FORMAT_UNKNOWN); + break; + } + } } } + + // Handle special cases based on flags + switch (format) + { + case DXGI_FORMAT_B8G8R8A8_UNORM: // BGRA + case DXGI_FORMAT_B8G8R8X8_UNORM: // BGRX + if (flags & WIC_FLAGS_FORCE_RGB) + { + format = DXGI_FORMAT_R8G8B8A8_UNORM; + if (pConvert) + memcpy(pConvert, &GUID_WICPixelFormat32bppRGBA, sizeof(WICPixelFormatGUID)); + } + break; + + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + if (flags & WIC_FLAGS_NO_X2_BIAS) + { + format = DXGI_FORMAT_R10G10B10A2_UNORM; + if (pConvert) + memcpy(pConvert, &GUID_WICPixelFormat32bppRGBA1010102, sizeof(WICPixelFormatGUID)); + } + break; + + case DXGI_FORMAT_B5G5R5A1_UNORM: + case DXGI_FORMAT_B5G6R5_UNORM: + if (flags & WIC_FLAGS_NO_16BPP) + { + format = DXGI_FORMAT_R8G8B8A8_UNORM; + if (pConvert) + memcpy(pConvert, &GUID_WICPixelFormat32bppRGBA, sizeof(WICPixelFormatGUID)); + } + break; + + case DXGI_FORMAT_R1_UNORM: + if (!(flags & WIC_FLAGS_ALLOW_MONO)) + { + // By default we want to promote a black & white to gresycale since R1 is not a generally supported D3D format + format = DXGI_FORMAT_R8_UNORM; + if (pConvert) + memcpy(pConvert, &GUID_WICPixelFormat8bppGray, sizeof(WICPixelFormatGUID)); + } + } + + return format; + } + + + //------------------------------------------------------------------------------------- + // Determines metadata for image + //------------------------------------------------------------------------------------- + HRESULT DecodeMetadata( + DWORD flags, + bool iswic2, + _In_ IWICBitmapDecoder *decoder, + _In_ IWICBitmapFrameDecode *frame, + _Out_ TexMetadata& metadata, + _Out_opt_ WICPixelFormatGUID* pConvert, + _In_opt_ std::function getMQR) + { + if (!decoder || !frame) + return E_POINTER; + + memset(&metadata, 0, sizeof(TexMetadata)); + metadata.depth = 1; + metadata.mipLevels = 1; + metadata.dimension = TEX_DIMENSION_TEXTURE2D; + + UINT w, h; + HRESULT hr = frame->GetSize(&w, &h); + if (FAILED(hr)) + return hr; + + metadata.width = w; + metadata.height = h; + + if (flags & WIC_FLAGS_ALL_FRAMES) + { + UINT fcount; + hr = decoder->GetFrameCount(&fcount); + if (FAILED(hr)) + return hr; + + metadata.arraySize = fcount; + } + else + metadata.arraySize = 1; + + WICPixelFormatGUID pixelFormat; + hr = frame->GetPixelFormat(&pixelFormat); + if (FAILED(hr)) + return hr; + + metadata.format = DetermineFormat(pixelFormat, flags, iswic2, pConvert); + if (metadata.format == DXGI_FORMAT_UNKNOWN) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + + if (!(flags & WIC_FLAGS_IGNORE_SRGB)) + { + GUID containerFormat; + hr = decoder->GetContainerFormat(&containerFormat); + if (FAILED(hr)) + return hr; + + ComPtr metareader; + hr = frame->GetMetadataQueryReader(metareader.GetAddressOf()); + if (SUCCEEDED(hr)) + { + // Check for sRGB colorspace metadata + bool sRGB = false; + + PROPVARIANT value; + PropVariantInit(&value); + + if (memcmp(&containerFormat, &GUID_ContainerFormatPng, sizeof(GUID)) == 0) + { + // Check for sRGB chunk + if (SUCCEEDED(metareader->GetMetadataByName(L"/sRGB/RenderingIntent", &value)) && value.vt == VT_UI1) + { + sRGB = true; + } + } +#if defined(_XBOX_ONE) && defined(_TITLE) + else if (memcmp(&containerFormat, &GUID_ContainerFormatJpeg, sizeof(GUID)) == 0) + { + if (SUCCEEDED(metareader->GetMetadataByName(L"/app1/ifd/exif/{ushort=40961}", &value)) && value.vt == VT_UI2 && value.uiVal == 1) + { + sRGB = true; + } + } + else if (memcmp(&containerFormat, &GUID_ContainerFormatTiff, sizeof(GUID)) == 0) + { + if (SUCCEEDED(metareader->GetMetadataByName(L"/ifd/exif/{ushort=40961}", &value)) && value.vt == VT_UI2 && value.uiVal == 1) + { + sRGB = true; + } + } +#else + else if (SUCCEEDED(metareader->GetMetadataByName(L"System.Image.ColorSpace", &value)) && value.vt == VT_UI2 && value.uiVal == 1) + { + sRGB = true; + } +#endif + + PropVariantClear(&value); + + if (sRGB) + metadata.format = MakeSRGB(metadata.format); + } + else if (hr == WINCODEC_ERR_UNSUPPORTEDOPERATION) + { + // Some formats just don't support metadata (BMP, ICO, etc.), so ignore this failure + hr = S_OK; + } + } + + if (getMQR) + { + ComPtr metareader; + if (SUCCEEDED(frame->GetMetadataQueryReader(metareader.GetAddressOf()))) + { + getMQR(metareader.Get()); + } + } + + return hr; + } + + + //------------------------------------------------------------------------------------- + // Decodes a single frame + //------------------------------------------------------------------------------------- + HRESULT DecodeSingleFrame( + DWORD flags, + const TexMetadata& metadata, + const WICPixelFormatGUID& convertGUID, + _In_ IWICBitmapFrameDecode *frame, + _Inout_ ScratchImage& image) + { + if (!frame) + return E_POINTER; + + HRESULT hr = image.Initialize2D(metadata.format, metadata.width, metadata.height, 1, 1); + if (FAILED(hr)) + return hr; + + const Image *img = image.GetImage(0, 0, 0); + if (!img) + return E_POINTER; + + bool iswic2 = false; + IWICImagingFactory* pWIC = GetWICFactory(iswic2); + if (!pWIC) + return E_NOINTERFACE; + + if (memcmp(&convertGUID, &GUID_NULL, sizeof(GUID)) == 0) + { + hr = frame->CopyPixels(0, static_cast(img->rowPitch), static_cast(img->slicePitch), img->pixels); + if (FAILED(hr)) + return hr; + } else { - for( size_t i=0; i < _countof(g_WICConvert); ++i ) - { - if ( memcmp( &g_WICConvert[i].source, &pixelFormat, sizeof(WICPixelFormatGUID) ) == 0 ) - { - if ( pConvert ) - memcpy( pConvert, &g_WICConvert[i].target, sizeof(WICPixelFormatGUID) ); + ComPtr FC; + hr = pWIC->CreateFormatConverter(FC.GetAddressOf()); + if (FAILED(hr)) + return hr; - format = _WICToDXGI( g_WICConvert[i].target ); - assert( format != DXGI_FORMAT_UNKNOWN ); - break; + WICPixelFormatGUID pixelFormat; + hr = frame->GetPixelFormat(&pixelFormat); + if (FAILED(hr)) + return hr; + + BOOL canConvert = FALSE; + hr = FC->CanConvert(pixelFormat, convertGUID, &canConvert); + if (FAILED(hr) || !canConvert) + { + return E_UNEXPECTED; + } + + hr = FC->Initialize(frame, convertGUID, _GetWICDither(flags), 0, 0, WICBitmapPaletteTypeCustom); + if (FAILED(hr)) + return hr; + + hr = FC->CopyPixels(0, static_cast(img->rowPitch), static_cast(img->slicePitch), img->pixels); + if (FAILED(hr)) + return hr; + } + + return S_OK; + } + + + //------------------------------------------------------------------------------------- + // Decodes an image array, resizing/format converting as needed + //------------------------------------------------------------------------------------- + HRESULT DecodeMultiframe( + DWORD flags, + const TexMetadata& metadata, + _In_ IWICBitmapDecoder *decoder, + _Inout_ ScratchImage& image) + { + if (!decoder) + return E_POINTER; + + HRESULT hr = image.Initialize2D(metadata.format, metadata.width, metadata.height, metadata.arraySize, 1); + if (FAILED(hr)) + return hr; + + bool iswic2 = false; + IWICImagingFactory* pWIC = GetWICFactory(iswic2); + if (!pWIC) + return E_NOINTERFACE; + + WICPixelFormatGUID sourceGUID; + if (!_DXGIToWIC(metadata.format, sourceGUID)) + return E_FAIL; + + for (size_t index = 0; index < metadata.arraySize; ++index) + { + const Image* img = image.GetImage(0, index, 0); + if (!img) + return E_POINTER; + + ComPtr frame; + hr = decoder->GetFrame(static_cast(index), frame.GetAddressOf()); + if (FAILED(hr)) + return hr; + + WICPixelFormatGUID pfGuid; + hr = frame->GetPixelFormat(&pfGuid); + if (FAILED(hr)) + return hr; + + UINT w, h; + hr = frame->GetSize(&w, &h); + if (FAILED(hr)) + return hr; + + if (w == metadata.width && h == metadata.height) + { + // This frame does not need resized + if (memcmp(&pfGuid, &sourceGUID, sizeof(WICPixelFormatGUID)) == 0) + { + hr = frame->CopyPixels(0, static_cast(img->rowPitch), static_cast(img->slicePitch), img->pixels); + if (FAILED(hr)) + return hr; + } + else + { + ComPtr FC; + hr = pWIC->CreateFormatConverter(FC.GetAddressOf()); + if (FAILED(hr)) + return hr; + + BOOL canConvert = FALSE; + hr = FC->CanConvert(pfGuid, sourceGUID, &canConvert); + if (FAILED(hr) || !canConvert) + { + return E_UNEXPECTED; + } + + hr = FC->Initialize(frame.Get(), sourceGUID, _GetWICDither(flags), 0, 0, WICBitmapPaletteTypeCustom); + if (FAILED(hr)) + return hr; + + hr = FC->CopyPixels(0, static_cast(img->rowPitch), static_cast(img->slicePitch), img->pixels); + if (FAILED(hr)) + return hr; + } + } + else + { + // This frame needs resizing + ComPtr scaler; + hr = pWIC->CreateBitmapScaler(scaler.GetAddressOf()); + if (FAILED(hr)) + return hr; + + hr = scaler->Initialize(frame.Get(), static_cast(metadata.width), static_cast(metadata.height), _GetWICInterp(flags)); + if (FAILED(hr)) + return hr; + + WICPixelFormatGUID pfScaler; + hr = scaler->GetPixelFormat(&pfScaler); + if (FAILED(hr)) + return hr; + + if (memcmp(&pfScaler, &sourceGUID, sizeof(WICPixelFormatGUID)) == 0) + { + hr = scaler->CopyPixels(0, static_cast(img->rowPitch), static_cast(img->slicePitch), img->pixels); + if (FAILED(hr)) + return hr; + } + else + { + // The WIC bitmap scaler is free to return a different pixel format than the source image, so here we + // convert it to our desired format + ComPtr FC; + hr = pWIC->CreateFormatConverter(FC.GetAddressOf()); + if (FAILED(hr)) + return hr; + + BOOL canConvert = FALSE; + hr = FC->CanConvert(pfScaler, sourceGUID, &canConvert); + if (FAILED(hr) || !canConvert) + { + return E_UNEXPECTED; + } + + hr = FC->Initialize(scaler.Get(), sourceGUID, _GetWICDither(flags), 0, 0, WICBitmapPaletteTypeCustom); + if (FAILED(hr)) + return hr; + + hr = FC->CopyPixels(0, static_cast(img->rowPitch), static_cast(img->slicePitch), img->pixels); + if (FAILED(hr)) + return hr; } } } + + return S_OK; } - // Handle special cases based on flags - switch (format) + + //------------------------------------------------------------------------------------- + // Encodes image metadata + //------------------------------------------------------------------------------------- + HRESULT EncodeMetadata( + _In_ IWICBitmapFrameEncode* frame, + const GUID& containerFormat, + DXGI_FORMAT format) { - case DXGI_FORMAT_B8G8R8A8_UNORM: // BGRA - case DXGI_FORMAT_B8G8R8X8_UNORM: // BGRX - if ( flags & WIC_FLAGS_FORCE_RGB ) + if (!frame) + return E_POINTER; + + ComPtr metawriter; + HRESULT hr = frame->GetMetadataQueryWriter(metawriter.GetAddressOf()); + if (SUCCEEDED(hr)) { - format = DXGI_FORMAT_R8G8B8A8_UNORM; - if ( pConvert ) - memcpy( pConvert, &GUID_WICPixelFormat32bppRGBA, sizeof(WICPixelFormatGUID) ); - } - break; - - case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: - if ( flags & WIC_FLAGS_NO_X2_BIAS ) - { - format = DXGI_FORMAT_R10G10B10A2_UNORM; - if ( pConvert ) - memcpy( pConvert, &GUID_WICPixelFormat32bppRGBA1010102, sizeof(WICPixelFormatGUID) ); - } - break; - - case DXGI_FORMAT_B5G5R5A1_UNORM: - case DXGI_FORMAT_B5G6R5_UNORM: - if ( flags & WIC_FLAGS_NO_16BPP ) - { - format = DXGI_FORMAT_R8G8B8A8_UNORM; - if ( pConvert ) - memcpy( pConvert, &GUID_WICPixelFormat32bppRGBA, sizeof(WICPixelFormatGUID) ); - } - break; - - case DXGI_FORMAT_R1_UNORM: - if ( !(flags & WIC_FLAGS_ALLOW_MONO ) ) - { - // By default we want to promote a black & white to gresycale since R1 is not a generally supported D3D format - format = DXGI_FORMAT_R8_UNORM; - if ( pConvert ) - memcpy( pConvert, &GUID_WICPixelFormat8bppGray, sizeof(WICPixelFormatGUID) ); - } - } - - return format; -} - - -//------------------------------------------------------------------------------------- -// Determines metadata for image -//------------------------------------------------------------------------------------- -static HRESULT _DecodeMetadata( _In_ DWORD flags, _In_ bool iswic2, - _In_ IWICBitmapDecoder *decoder, _In_ IWICBitmapFrameDecode *frame, - _Out_ TexMetadata& metadata, _Out_opt_ WICPixelFormatGUID* pConvert, - _In_opt_ std::function getMQR ) -{ - if ( !decoder || !frame ) - return E_POINTER; - - memset( &metadata, 0, sizeof(TexMetadata) ); - metadata.depth = 1; - metadata.mipLevels = 1; - metadata.dimension = TEX_DIMENSION_TEXTURE2D; - - UINT w, h; - HRESULT hr = frame->GetSize( &w, &h ); - if ( FAILED(hr) ) - return hr; - - metadata.width = w; - metadata.height = h; - - if ( flags & WIC_FLAGS_ALL_FRAMES ) - { - UINT fcount; - hr = decoder->GetFrameCount( &fcount ); - if ( FAILED(hr) ) - return hr; - - metadata.arraySize = fcount; - } - else - metadata.arraySize = 1; - - WICPixelFormatGUID pixelFormat; - hr = frame->GetPixelFormat( &pixelFormat ); - if ( FAILED(hr) ) - return hr; - - metadata.format = _DetermineFormat( pixelFormat, flags, iswic2, pConvert ); - if ( metadata.format == DXGI_FORMAT_UNKNOWN ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); - - if ( !( flags & WIC_FLAGS_IGNORE_SRGB ) ) - { - GUID containerFormat; - hr = decoder->GetContainerFormat( &containerFormat ); - if ( FAILED(hr) ) - return hr; - - ComPtr metareader; - hr = frame->GetMetadataQueryReader( metareader.GetAddressOf() ); - if ( SUCCEEDED(hr) ) - { - // Check for sRGB colorspace metadata - bool sRGB = false; - PROPVARIANT value; - PropVariantInit( &value ); + PropVariantInit(&value); - if ( memcmp( &containerFormat, &GUID_ContainerFormatPng, sizeof(GUID) ) == 0 ) + bool sRGB = IsSRGB(format); + + value.vt = VT_LPSTR; + value.pszVal = "DirectXTex"; + + if (memcmp(&containerFormat, &GUID_ContainerFormatPng, sizeof(GUID)) == 0) { - // Check for sRGB chunk - if ( SUCCEEDED( metareader->GetMetadataByName( L"/sRGB/RenderingIntent", &value ) ) && value.vt == VT_UI1 ) + // Set Software name + (void)metawriter->SetMetadataByName(L"/tEXt/{str=Software}", &value); + + // Set sRGB chunk + if (sRGB) { - sRGB = true; + value.vt = VT_UI1; + value.bVal = 0; + (void)metawriter->SetMetadataByName(L"/sRGB/RenderingIntent", &value); } } #if defined(_XBOX_ONE) && defined(_TITLE) - else if ( memcmp( &containerFormat, &GUID_ContainerFormatJpeg, sizeof(GUID) ) == 0 ) + else if (memcmp(&containerFormat, &GUID_ContainerFormatJpeg, sizeof(GUID)) == 0) { - if ( SUCCEEDED( metareader->GetMetadataByName( L"/app1/ifd/exif/{ushort=40961}", &value ) ) && value.vt == VT_UI2 && value.uiVal == 1 ) + // Set Software name + (void)metawriter->SetMetadataByName(L"/app1/ifd/{ushort=305}", &value); + + if (sRGB) { - sRGB = true; + // Set EXIF Colorspace of sRGB + value.vt = VT_UI2; + value.uiVal = 1; + (void)metawriter->SetMetadataByName(L"/app1/ifd/exif/{ushort=40961}", &value); } } - else if ( memcmp( &containerFormat, &GUID_ContainerFormatTiff, sizeof(GUID) ) == 0 ) + else if (memcmp(&containerFormat, &GUID_ContainerFormatTiff, sizeof(GUID)) == 0) { - if ( SUCCEEDED( metareader->GetMetadataByName( L"/ifd/exif/{ushort=40961}", &value ) ) && value.vt == VT_UI2 && value.uiVal == 1 ) + // Set Software name + (void)metawriter->SetMetadataByName(L"/ifd/{ushort=305}", &value); + + if (sRGB) { - sRGB = true; + // Set EXIF Colorspace of sRGB + value.vt = VT_UI2; + value.uiVal = 1; + (void)metawriter->SetMetadataByName(L"/ifd/exif/{ushort=40961}", &value); } } #else - else if ( SUCCEEDED( metareader->GetMetadataByName( L"System.Image.ColorSpace", &value ) ) && value.vt == VT_UI2 && value.uiVal == 1 ) + else { - sRGB = true; + // Set Software name + (void)metawriter->SetMetadataByName(L"System.ApplicationName", &value); + + if (sRGB) + { + // Set EXIF Colorspace of sRGB + value.vt = VT_UI2; + value.uiVal = 1; + (void)metawriter->SetMetadataByName(L"System.Image.ColorSpace", &value); + } } #endif - - PropVariantClear( &value ); - - if ( sRGB ) - metadata.format = MakeSRGB( metadata.format ); } - else if ( hr == WINCODEC_ERR_UNSUPPORTEDOPERATION ) + else if (hr == WINCODEC_ERR_UNSUPPORTEDOPERATION) { // Some formats just don't support metadata (BMP, ICO, etc.), so ignore this failure hr = S_OK; } - } - if (getMQR) - { - ComPtr metareader; - if (SUCCEEDED(frame->GetMetadataQueryReader(metareader.GetAddressOf()))) - { - getMQR(metareader.Get()); - } - } - - return hr; -} - - -//------------------------------------------------------------------------------------- -// Decodes a single frame -//------------------------------------------------------------------------------------- -static HRESULT _DecodeSingleFrame( _In_ DWORD flags, _In_ const TexMetadata& metadata, _In_ const WICPixelFormatGUID& convertGUID, - _In_ IWICBitmapFrameDecode *frame, _Inout_ ScratchImage& image ) -{ - if ( !frame ) - return E_POINTER; - - HRESULT hr = image.Initialize2D( metadata.format, metadata.width, metadata.height, 1, 1 ); - if ( FAILED(hr) ) return hr; - - const Image *img = image.GetImage( 0, 0, 0 ); - if ( !img ) - return E_POINTER; - - bool iswic2 = false; - IWICImagingFactory* pWIC = GetWICFactory(iswic2); - if ( !pWIC ) - return E_NOINTERFACE; - - if ( memcmp( &convertGUID, &GUID_NULL, sizeof(GUID) ) == 0 ) - { - hr = frame->CopyPixels( 0, static_cast( img->rowPitch ), static_cast( img->slicePitch ), img->pixels ); - if ( FAILED(hr) ) - return hr; - } - else - { - ComPtr FC; - hr = pWIC->CreateFormatConverter( FC.GetAddressOf() ); - if ( FAILED(hr) ) - return hr; - - WICPixelFormatGUID pixelFormat; - hr = frame->GetPixelFormat( &pixelFormat ); - if ( FAILED(hr) ) - return hr; - - BOOL canConvert = FALSE; - hr = FC->CanConvert( pixelFormat, convertGUID, &canConvert ); - if ( FAILED(hr) || !canConvert ) - { - return E_UNEXPECTED; - } - - hr = FC->Initialize( frame, convertGUID, _GetWICDither( flags ), 0, 0, WICBitmapPaletteTypeCustom ); - if ( FAILED(hr) ) - return hr; - - hr = FC->CopyPixels( 0, static_cast( img->rowPitch ), static_cast( img->slicePitch ), img->pixels ); - if ( FAILED(hr) ) - return hr; } - return S_OK; -} - -//------------------------------------------------------------------------------------- -// Decodes an image array, resizing/format converting as needed -//------------------------------------------------------------------------------------- -static HRESULT _DecodeMultiframe( _In_ DWORD flags, _In_ const TexMetadata& metadata, - _In_ IWICBitmapDecoder *decoder, _Inout_ ScratchImage& image ) -{ - if ( !decoder ) - return E_POINTER; - - HRESULT hr = image.Initialize2D( metadata.format, metadata.width, metadata.height, metadata.arraySize, 1 ); - if ( FAILED(hr) ) - return hr; - - bool iswic2 = false; - IWICImagingFactory* pWIC = GetWICFactory(iswic2); - if ( !pWIC ) - return E_NOINTERFACE; - - WICPixelFormatGUID sourceGUID; - if ( !_DXGIToWIC( metadata.format, sourceGUID ) ) - return E_FAIL; - - for( size_t index = 0; index < metadata.arraySize; ++index ) + //------------------------------------------------------------------------------------- + // Encodes a single frame + //------------------------------------------------------------------------------------- + HRESULT EncodeImage( + const Image& image, + DWORD flags, + _In_ REFGUID containerFormat, + _In_ IWICBitmapFrameEncode* frame, + _In_opt_ IPropertyBag2* props, + _In_opt_ const GUID* targetFormat) { - const Image* img = image.GetImage( 0, index, 0 ); - if ( !img ) + if (!frame) + return E_INVALIDARG; + + if (!image.pixels) return E_POINTER; - ComPtr frame; - hr = decoder->GetFrame( static_cast( index ), frame.GetAddressOf() ); - if ( FAILED(hr) ) - return hr; - WICPixelFormatGUID pfGuid; - hr = frame->GetPixelFormat( &pfGuid ); - if ( FAILED(hr) ) + if (!_DXGIToWIC(image.format, pfGuid)) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + + HRESULT hr = frame->Initialize(props); + if (FAILED(hr)) return hr; - UINT w, h; - hr = frame->GetSize( &w, &h ); - if ( FAILED(hr) ) + if ((image.width > UINT32_MAX) || (image.height > UINT32_MAX)) + return E_INVALIDARG; + + hr = frame->SetSize(static_cast(image.width), static_cast(image.height)); + if (FAILED(hr)) return hr; - if ( w == metadata.width && h == metadata.height ) + hr = frame->SetResolution(72, 72); + if (FAILED(hr)) + return hr; + + WICPixelFormatGUID targetGuid = (targetFormat) ? (*targetFormat) : pfGuid; + hr = frame->SetPixelFormat(&targetGuid); + if (FAILED(hr)) + return hr; + + if (targetFormat && memcmp(targetFormat, &targetGuid, sizeof(WICPixelFormatGUID)) != 0) { - // This frame does not need resized - if ( memcmp( &pfGuid, &sourceGUID, sizeof(WICPixelFormatGUID) ) == 0 ) - { - hr = frame->CopyPixels( 0, static_cast( img->rowPitch ), static_cast( img->slicePitch ), img->pixels ); - if ( FAILED(hr) ) - return hr; - } - else - { - ComPtr FC; - hr = pWIC->CreateFormatConverter( FC.GetAddressOf() ); - if ( FAILED(hr) ) - return hr; + // Requested output pixel format is not supported by the WIC codec + return E_FAIL; + } - BOOL canConvert = FALSE; - hr = FC->CanConvert( pfGuid, sourceGUID, &canConvert ); - if ( FAILED(hr) || !canConvert ) - { - return E_UNEXPECTED; - } + hr = EncodeMetadata(frame, containerFormat, image.format); + if (FAILED(hr)) + return hr; - hr = FC->Initialize( frame.Get(), sourceGUID, _GetWICDither( flags ), 0, 0, WICBitmapPaletteTypeCustom ); - if ( FAILED(hr) ) - return hr; - - hr = FC->CopyPixels( 0, static_cast( img->rowPitch ), static_cast( img->slicePitch ), img->pixels ); - if ( FAILED(hr) ) - return hr; + if (memcmp(&targetGuid, &pfGuid, sizeof(WICPixelFormatGUID)) != 0) + { + // Conversion required to write + bool iswic2 = false; + IWICImagingFactory* pWIC = GetWICFactory(iswic2); + if (!pWIC) + return E_NOINTERFACE; + + ComPtr source; + hr = pWIC->CreateBitmapFromMemory(static_cast(image.width), static_cast(image.height), pfGuid, + static_cast(image.rowPitch), static_cast(image.slicePitch), + image.pixels, source.GetAddressOf()); + if (FAILED(hr)) + return hr; + + ComPtr FC; + hr = pWIC->CreateFormatConverter(FC.GetAddressOf()); + if (FAILED(hr)) + return hr; + + BOOL canConvert = FALSE; + hr = FC->CanConvert(pfGuid, targetGuid, &canConvert); + if (FAILED(hr) || !canConvert) + { + return E_UNEXPECTED; } + + hr = FC->Initialize(source.Get(), targetGuid, _GetWICDither(flags), 0, 0, WICBitmapPaletteTypeCustom); + if (FAILED(hr)) + return hr; + + WICRect rect = { 0, 0, static_cast(image.width), static_cast(image.height) }; + hr = frame->WriteSource(FC.Get(), &rect); + if (FAILED(hr)) + return hr; } else { - // This frame needs resizing - ComPtr scaler; - hr = pWIC->CreateBitmapScaler( scaler.GetAddressOf() ); - if ( FAILED(hr) ) + // No conversion required + hr = frame->WritePixels(static_cast(image.height), static_cast(image.rowPitch), static_cast(image.slicePitch), + reinterpret_cast(image.pixels)); + if (FAILED(hr)) return hr; - - hr = scaler->Initialize( frame.Get(), static_cast( metadata.width ), static_cast( metadata.height ), _GetWICInterp( flags ) ); - if ( FAILED(hr) ) - return hr; - - WICPixelFormatGUID pfScaler; - hr = scaler->GetPixelFormat( &pfScaler ); - if ( FAILED(hr) ) - return hr; - - if ( memcmp( &pfScaler, &sourceGUID, sizeof(WICPixelFormatGUID) ) == 0 ) - { - hr = scaler->CopyPixels( 0, static_cast( img->rowPitch ), static_cast( img->slicePitch ), img->pixels ); - if ( FAILED(hr) ) - return hr; - } - else - { - // The WIC bitmap scaler is free to return a different pixel format than the source image, so here we - // convert it to our desired format - ComPtr FC; - hr = pWIC->CreateFormatConverter( FC.GetAddressOf() ); - if ( FAILED(hr) ) - return hr; - - BOOL canConvert = FALSE; - hr = FC->CanConvert( pfScaler, sourceGUID, &canConvert ); - if ( FAILED(hr) || !canConvert ) - { - return E_UNEXPECTED; - } - - hr = FC->Initialize( scaler.Get(), sourceGUID, _GetWICDither( flags ), 0, 0, WICBitmapPaletteTypeCustom ); - if ( FAILED(hr) ) - return hr; - - hr = FC->CopyPixels( 0, static_cast( img->rowPitch ), static_cast( img->slicePitch ), img->pixels ); - if ( FAILED(hr) ) - return hr; - } } + + hr = frame->Commit(); + if (FAILED(hr)) + return hr; + + return S_OK; } - return S_OK; -} - - -//------------------------------------------------------------------------------------- -// Encodes image metadata -//------------------------------------------------------------------------------------- -static HRESULT _EncodeMetadata( _In_ IWICBitmapFrameEncode* frame, _In_ const GUID& containerFormat, _In_ DXGI_FORMAT format ) -{ - if ( !frame ) - return E_POINTER; - - ComPtr metawriter; - HRESULT hr = frame->GetMetadataQueryWriter( metawriter.GetAddressOf() ); - if ( SUCCEEDED( hr ) ) + HRESULT EncodeSingleFrame( + const Image& image, + DWORD flags, + _In_ REFGUID containerFormat, + _Inout_ IStream* stream, + _In_opt_ const GUID* targetFormat, + _In_opt_ std::function setCustomProps) { - PROPVARIANT value; - PropVariantInit( &value ); + if (!stream) + return E_INVALIDARG; - bool sRGB = IsSRGB( format ); - - value.vt = VT_LPSTR; - value.pszVal = "DirectXTex"; - - if ( memcmp( &containerFormat, &GUID_ContainerFormatPng, sizeof(GUID) ) == 0 ) - { - // Set Software name - (void)metawriter->SetMetadataByName( L"/tEXt/{str=Software}", &value ); - - // Set sRGB chunk - if ( sRGB ) - { - value.vt = VT_UI1; - value.bVal = 0; - (void)metawriter->SetMetadataByName( L"/sRGB/RenderingIntent", &value ); - } - } -#if defined(_XBOX_ONE) && defined(_TITLE) - else if ( memcmp( &containerFormat, &GUID_ContainerFormatJpeg, sizeof(GUID) ) == 0 ) - { - // Set Software name - (void)metawriter->SetMetadataByName( L"/app1/ifd/{ushort=305}", &value ); - - if ( sRGB ) - { - // Set EXIF Colorspace of sRGB - value.vt = VT_UI2; - value.uiVal = 1; - (void)metawriter->SetMetadataByName( L"/app1/ifd/exif/{ushort=40961}", &value ); - } - } - else if ( memcmp( &containerFormat, &GUID_ContainerFormatTiff, sizeof(GUID) ) == 0 ) - { - // Set Software name - (void)metawriter->SetMetadataByName( L"/ifd/{ushort=305}", &value ); - - if ( sRGB ) - { - // Set EXIF Colorspace of sRGB - value.vt = VT_UI2; - value.uiVal = 1; - (void)metawriter->SetMetadataByName( L"/ifd/exif/{ushort=40961}", &value ); - } - } -#else - else - { - // Set Software name - (void)metawriter->SetMetadataByName( L"System.ApplicationName", &value ); - - if ( sRGB ) - { - // Set EXIF Colorspace of sRGB - value.vt = VT_UI2; - value.uiVal = 1; - (void)metawriter->SetMetadataByName( L"System.Image.ColorSpace", &value ); - } - } -#endif - } - else if ( hr == WINCODEC_ERR_UNSUPPORTEDOPERATION ) - { - // Some formats just don't support metadata (BMP, ICO, etc.), so ignore this failure - hr = S_OK; - } - - return hr; -} - - -//------------------------------------------------------------------------------------- -// Encodes a single frame -//------------------------------------------------------------------------------------- -static HRESULT _EncodeImage( _In_ const Image& image, _In_ DWORD flags, _In_ REFGUID containerFormat, - _In_ IWICBitmapFrameEncode* frame, _In_opt_ IPropertyBag2* props, _In_opt_ const GUID* targetFormat ) -{ - if ( !frame ) - return E_INVALIDARG; - - if ( !image.pixels ) - return E_POINTER; - - WICPixelFormatGUID pfGuid; - if ( !_DXGIToWIC( image.format, pfGuid ) ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); - - HRESULT hr = frame->Initialize( props ); - if ( FAILED(hr) ) - return hr; - - if ( (image.width > UINT32_MAX) || (image.height > UINT32_MAX) ) - return E_INVALIDARG; - - hr = frame->SetSize( static_cast( image.width ), static_cast( image.height ) ); - if ( FAILED(hr) ) - return hr; - - hr = frame->SetResolution( 72, 72 ); - if ( FAILED(hr) ) - return hr; - - WICPixelFormatGUID targetGuid = (targetFormat) ? (*targetFormat) : pfGuid; - hr = frame->SetPixelFormat( &targetGuid ); - if ( FAILED(hr) ) - return hr; - - if ( targetFormat && memcmp( targetFormat, &targetGuid, sizeof(WICPixelFormatGUID) ) != 0 ) - { - // Requested output pixel format is not supported by the WIC codec - return E_FAIL; - } - - hr = _EncodeMetadata( frame, containerFormat, image.format ); - if ( FAILED(hr) ) - return hr; - - if ( memcmp( &targetGuid, &pfGuid, sizeof(WICPixelFormatGUID) ) != 0 ) - { - // Conversion required to write + // Initialize WIC bool iswic2 = false; IWICImagingFactory* pWIC = GetWICFactory(iswic2); - if ( !pWIC ) + if (!pWIC) return E_NOINTERFACE; - ComPtr source; - hr = pWIC->CreateBitmapFromMemory( static_cast( image.width ), static_cast( image.height ), pfGuid, - static_cast( image.rowPitch ), static_cast( image.slicePitch ), - image.pixels, source.GetAddressOf() ); - if ( FAILED(hr) ) + ComPtr encoder; + HRESULT hr = pWIC->CreateEncoder(containerFormat, 0, encoder.GetAddressOf()); + if (FAILED(hr)) return hr; - ComPtr FC; - hr = pWIC->CreateFormatConverter( FC.GetAddressOf() ); - if ( FAILED(hr) ) + hr = encoder->Initialize(stream, WICBitmapEncoderNoCache); + if (FAILED(hr)) return hr; - BOOL canConvert = FALSE; - hr = FC->CanConvert( pfGuid, targetGuid, &canConvert ); - if ( FAILED(hr) || !canConvert ) - { - return E_UNEXPECTED; - } - - hr = FC->Initialize( source.Get(), targetGuid, _GetWICDither( flags ), 0, 0, WICBitmapPaletteTypeCustom ); - if ( FAILED(hr) ) - return hr; - - WICRect rect = { 0, 0, static_cast( image.width ), static_cast( image.height ) }; - hr = frame->WriteSource( FC.Get(), &rect ); - if ( FAILED(hr) ) - return hr; - } - else - { - // No conversion required - hr = frame->WritePixels( static_cast( image.height ), static_cast( image.rowPitch ), static_cast( image.slicePitch ), - reinterpret_cast( image.pixels ) ); - if ( FAILED(hr) ) - return hr; - } - - hr = frame->Commit(); - if ( FAILED(hr) ) - return hr; - - return S_OK; -} - -static HRESULT _EncodeSingleFrame( _In_ const Image& image, _In_ DWORD flags, - _In_ REFGUID containerFormat, _Inout_ IStream* stream, - _In_opt_ const GUID* targetFormat, _In_opt_ std::function setCustomProps ) -{ - if ( !stream ) - return E_INVALIDARG; - - // Initialize WIC - bool iswic2 = false; - IWICImagingFactory* pWIC = GetWICFactory(iswic2); - if ( !pWIC ) - return E_NOINTERFACE; - - ComPtr encoder; - HRESULT hr = pWIC->CreateEncoder( containerFormat, 0, encoder.GetAddressOf() ); - if ( FAILED(hr) ) - return hr; - - hr = encoder->Initialize( stream, WICBitmapEncoderNoCache ); - if ( FAILED(hr) ) - return hr; - - ComPtr frame; - ComPtr props; - hr = encoder->CreateNewFrame( frame.GetAddressOf(), props.GetAddressOf() ); - if ( FAILED(hr) ) - return hr; - - if ( memcmp( &containerFormat, &GUID_ContainerFormatBmp, sizeof(WICPixelFormatGUID) ) == 0 && iswic2 ) - { - // Opt-in to the WIC2 support for writing 32-bit Windows BMP files with an alpha channel - PROPBAG2 option = { 0 }; - option.pstrName = L"EnableV5Header32bppBGRA"; - - VARIANT varValue; - varValue.vt = VT_BOOL; - varValue.boolVal = VARIANT_TRUE; - (void)props->Write( 1, &option, &varValue ); - } - - if ( setCustomProps ) - { - setCustomProps( props.Get() ); - } - - hr = _EncodeImage( image, flags, containerFormat, frame.Get(), props.Get(), targetFormat ); - if ( FAILED(hr) ) - return hr; - - hr = encoder->Commit(); - if ( FAILED(hr) ) - return hr; - - return S_OK; -} - - -//------------------------------------------------------------------------------------- -// Encodes an image array -//------------------------------------------------------------------------------------- -static HRESULT _EncodeMultiframe( _In_reads_(nimages) const Image* images, _In_ size_t nimages, _In_ DWORD flags, - _In_ REFGUID containerFormat, _Inout_ IStream* stream, - _In_opt_ const GUID* targetFormat, _In_opt_ std::function setCustomProps ) -{ - if ( !stream || nimages < 2 ) - return E_INVALIDARG; - - if ( !images ) - return E_POINTER; - - // Initialize WIC - bool iswic2 = false; - IWICImagingFactory* pWIC = GetWICFactory(iswic2); - if ( !pWIC ) - return E_NOINTERFACE; - - ComPtr encoder; - HRESULT hr = pWIC->CreateEncoder( containerFormat, 0, encoder.GetAddressOf() ); - if ( FAILED(hr) ) - return hr; - - ComPtr einfo; - hr = encoder->GetEncoderInfo( einfo.GetAddressOf() ); - if ( FAILED(hr) ) - return hr; - - BOOL mframe = FALSE; - hr = einfo->DoesSupportMultiframe( &mframe ); - if ( FAILED(hr) ) - return hr; - - if ( !mframe ) - return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); - - hr = encoder->Initialize( stream, WICBitmapEncoderNoCache ); - if ( FAILED(hr) ) - return hr; - - for( size_t index=0; index < nimages; ++index ) - { ComPtr frame; ComPtr props; - hr = encoder->CreateNewFrame( frame.GetAddressOf(), props.GetAddressOf() ); - if ( FAILED(hr) ) + hr = encoder->CreateNewFrame(frame.GetAddressOf(), props.GetAddressOf()); + if (FAILED(hr)) return hr; - if ( setCustomProps ) + if (memcmp(&containerFormat, &GUID_ContainerFormatBmp, sizeof(WICPixelFormatGUID)) == 0 && iswic2) { - setCustomProps( props.Get() ); + // Opt-in to the WIC2 support for writing 32-bit Windows BMP files with an alpha channel + PROPBAG2 option = { 0 }; + option.pstrName = L"EnableV5Header32bppBGRA"; + + VARIANT varValue; + varValue.vt = VT_BOOL; + varValue.boolVal = VARIANT_TRUE; + (void)props->Write(1, &option, &varValue); } - hr = _EncodeImage( images[index], flags, containerFormat, frame.Get(), props.Get(), targetFormat ); - if ( FAILED(hr) ) + if (setCustomProps) + { + setCustomProps(props.Get()); + } + + hr = EncodeImage(image, flags, containerFormat, frame.Get(), props.Get(), targetFormat); + if (FAILED(hr)) return hr; + + hr = encoder->Commit(); + if (FAILED(hr)) + return hr; + + return S_OK; } - hr = encoder->Commit(); - if ( FAILED(hr) ) - return hr; - return S_OK; + //------------------------------------------------------------------------------------- + // Encodes an image array + //------------------------------------------------------------------------------------- + HRESULT EncodeMultiframe( + _In_reads_(nimages) const Image* images, + size_t nimages, + DWORD flags, + _In_ REFGUID containerFormat, + _Inout_ IStream* stream, + _In_opt_ const GUID* targetFormat, + _In_opt_ std::function setCustomProps) + { + if (!stream || nimages < 2) + return E_INVALIDARG; + + if (!images) + return E_POINTER; + + // Initialize WIC + bool iswic2 = false; + IWICImagingFactory* pWIC = GetWICFactory(iswic2); + if (!pWIC) + return E_NOINTERFACE; + + ComPtr encoder; + HRESULT hr = pWIC->CreateEncoder(containerFormat, 0, encoder.GetAddressOf()); + if (FAILED(hr)) + return hr; + + ComPtr einfo; + hr = encoder->GetEncoderInfo(einfo.GetAddressOf()); + if (FAILED(hr)) + return hr; + + BOOL mframe = FALSE; + hr = einfo->DoesSupportMultiframe(&mframe); + if (FAILED(hr)) + return hr; + + if (!mframe) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + + hr = encoder->Initialize(stream, WICBitmapEncoderNoCache); + if (FAILED(hr)) + return hr; + + for (size_t index = 0; index < nimages; ++index) + { + ComPtr frame; + ComPtr props; + hr = encoder->CreateNewFrame(frame.GetAddressOf(), props.GetAddressOf()); + if (FAILED(hr)) + return hr; + + if (setCustomProps) + { + setCustomProps(props.Get()); + } + + hr = EncodeImage(images[index], flags, containerFormat, frame.Get(), props.Get(), targetFormat); + if (FAILED(hr)) + return hr; + } + + hr = encoder->Commit(); + if (FAILED(hr)) + return hr; + + return S_OK; + } } @@ -855,44 +887,49 @@ static HRESULT _EncodeMultiframe( _In_reads_(nimages) const Image* images, _In_ // Obtain metadata from WIC-supported file in memory //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT GetMetadataFromWICMemory( LPCVOID pSource, size_t size, DWORD flags, TexMetadata& metadata, std::function getMQR ) +HRESULT DirectX::GetMetadataFromWICMemory( + const void* pSource, + size_t size, + DWORD flags, + TexMetadata& metadata, + std::function getMQR) { - if ( !pSource || size == 0 ) + if (!pSource || size == 0) return E_INVALIDARG; - if ( size > UINT32_MAX ) - return HRESULT_FROM_WIN32( ERROR_FILE_TOO_LARGE ); + if (size > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE); bool iswic2 = false; IWICImagingFactory* pWIC = GetWICFactory(iswic2); - if ( !pWIC ) + if (!pWIC) return E_NOINTERFACE; // Create input stream for memory ComPtr stream; - HRESULT hr = pWIC->CreateStream( stream.GetAddressOf() ); - if ( FAILED(hr) ) + HRESULT hr = pWIC->CreateStream(stream.GetAddressOf()); + if (FAILED(hr)) return hr; - hr = stream->InitializeFromMemory( reinterpret_cast( const_cast( pSource ) ), - static_cast( size ) ); - if ( FAILED(hr) ) + hr = stream->InitializeFromMemory(reinterpret_cast(const_cast(pSource)), + static_cast(size)); + if (FAILED(hr)) return hr; // Initialize WIC ComPtr decoder; - hr = pWIC->CreateDecoderFromStream( stream.Get(), 0, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf() ); - if ( FAILED(hr) ) + hr = pWIC->CreateDecoderFromStream(stream.Get(), 0, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf()); + if (FAILED(hr)) return hr; ComPtr frame; - hr = decoder->GetFrame( 0, frame.GetAddressOf() ); - if ( FAILED(hr) ) + hr = decoder->GetFrame(0, frame.GetAddressOf()); + if (FAILED(hr)) return hr; // Get metadata - hr = _DecodeMetadata( flags, iswic2, decoder.Get(), frame.Get(), metadata, nullptr, getMQR ); - if ( FAILED(hr) ) + hr = DecodeMetadata(flags, iswic2, decoder.Get(), frame.Get(), metadata, nullptr, getMQR); + if (FAILED(hr)) return hr; return S_OK; @@ -903,30 +940,34 @@ HRESULT GetMetadataFromWICMemory( LPCVOID pSource, size_t size, DWORD flags, Tex // Obtain metadata from WIC-supported file on disk //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT GetMetadataFromWICFile( LPCWSTR szFile, DWORD flags, TexMetadata& metadata, std::function getMQR ) +HRESULT DirectX::GetMetadataFromWICFile( + const wchar_t* szFile, + DWORD flags, + TexMetadata& metadata, + std::function getMQR) { - if ( !szFile ) + if (!szFile) return E_INVALIDARG; bool iswic2 = false; IWICImagingFactory* pWIC = GetWICFactory(iswic2); - if ( !pWIC ) + if (!pWIC) return E_NOINTERFACE; - + // Initialize WIC ComPtr decoder; - HRESULT hr = pWIC->CreateDecoderFromFilename( szFile, 0, GENERIC_READ, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf() ); - if ( FAILED(hr) ) + HRESULT hr = pWIC->CreateDecoderFromFilename(szFile, 0, GENERIC_READ, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf()); + if (FAILED(hr)) return hr; ComPtr frame; - hr = decoder->GetFrame( 0, frame.GetAddressOf() ); - if ( FAILED(hr) ) + hr = decoder->GetFrame(0, frame.GetAddressOf()); + if (FAILED(hr)) return hr; // Get metadata - hr = _DecodeMetadata( flags, iswic2, decoder.Get(), frame.Get(), metadata, nullptr, getMQR ); - if ( FAILED(hr) ) + hr = DecodeMetadata(flags, iswic2, decoder.Get(), frame.Get(), metadata, nullptr, getMQR); + if (FAILED(hr)) return hr; return S_OK; @@ -937,66 +978,72 @@ HRESULT GetMetadataFromWICFile( LPCWSTR szFile, DWORD flags, TexMetadata& metada // Load a WIC-supported file in memory //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT LoadFromWICMemory( LPCVOID pSource, size_t size, DWORD flags, TexMetadata* metadata, ScratchImage& image, std::function getMQR ) +HRESULT DirectX::LoadFromWICMemory( + const void* pSource, + size_t size, + DWORD flags, + TexMetadata* metadata, + ScratchImage& image, + std::function getMQR) { - if ( !pSource || size == 0 ) + if (!pSource || size == 0) return E_INVALIDARG; - if ( size > UINT32_MAX ) - return HRESULT_FROM_WIN32( ERROR_FILE_TOO_LARGE ); + if (size > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE); bool iswic2 = false; IWICImagingFactory* pWIC = GetWICFactory(iswic2); - if ( !pWIC ) + if (!pWIC) return E_NOINTERFACE; image.Release(); // Create input stream for memory ComPtr stream; - HRESULT hr = pWIC->CreateStream( stream.GetAddressOf() ); - if ( FAILED(hr) ) + HRESULT hr = pWIC->CreateStream(stream.GetAddressOf()); + if (FAILED(hr)) return hr; - hr = stream->InitializeFromMemory( reinterpret_cast( const_cast( pSource ) ), static_cast( size ) ); - if ( FAILED(hr) ) + hr = stream->InitializeFromMemory(reinterpret_cast(const_cast(pSource)), static_cast(size)); + if (FAILED(hr)) return hr; // Initialize WIC ComPtr decoder; - hr = pWIC->CreateDecoderFromStream( stream.Get(), 0, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf() ); - if ( FAILED(hr) ) + hr = pWIC->CreateDecoderFromStream(stream.Get(), 0, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf()); + if (FAILED(hr)) return hr; ComPtr frame; - hr = decoder->GetFrame( 0, frame.GetAddressOf() ); - if ( FAILED(hr) ) + hr = decoder->GetFrame(0, frame.GetAddressOf()); + if (FAILED(hr)) return hr; // Get metadata TexMetadata mdata; - WICPixelFormatGUID convertGUID = {0}; - hr = _DecodeMetadata( flags, iswic2, decoder.Get(), frame.Get(), mdata, &convertGUID, getMQR ); - if ( FAILED(hr) ) + WICPixelFormatGUID convertGUID = { 0 }; + hr = DecodeMetadata(flags, iswic2, decoder.Get(), frame.Get(), mdata, &convertGUID, getMQR); + if (FAILED(hr)) return hr; - if ( (mdata.arraySize > 1) && (flags & WIC_FLAGS_ALL_FRAMES) ) + if ((mdata.arraySize > 1) && (flags & WIC_FLAGS_ALL_FRAMES)) { - hr = _DecodeMultiframe( flags, mdata, decoder.Get(), image ); + hr = DecodeMultiframe(flags, mdata, decoder.Get(), image); } else { - hr = _DecodeSingleFrame( flags, mdata, convertGUID, frame.Get(), image ); + hr = DecodeSingleFrame(flags, mdata, convertGUID, frame.Get(), image); } - if ( FAILED(hr) ) + if (FAILED(hr)) { image.Release(); return hr; } - if ( metadata ) - memcpy( metadata, &mdata, sizeof(TexMetadata) ); + if (metadata) + memcpy(metadata, &mdata, sizeof(TexMetadata)); return S_OK; } @@ -1006,53 +1053,58 @@ HRESULT LoadFromWICMemory( LPCVOID pSource, size_t size, DWORD flags, TexMetadat // Load a WIC-supported file from disk //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT LoadFromWICFile( LPCWSTR szFile, DWORD flags, TexMetadata* metadata, ScratchImage& image, std::function getMQR ) +HRESULT DirectX::LoadFromWICFile( + const wchar_t* szFile, + DWORD flags, + TexMetadata* metadata, + ScratchImage& image, + std::function getMQR) { - if ( !szFile ) + if (!szFile) return E_INVALIDARG; bool iswic2 = false; IWICImagingFactory* pWIC = GetWICFactory(iswic2); - if ( !pWIC ) + if (!pWIC) return E_NOINTERFACE; - + image.Release(); // Initialize WIC ComPtr decoder; - HRESULT hr = pWIC->CreateDecoderFromFilename( szFile, 0, GENERIC_READ, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf() ); - if ( FAILED(hr) ) + HRESULT hr = pWIC->CreateDecoderFromFilename(szFile, 0, GENERIC_READ, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf()); + if (FAILED(hr)) return hr; ComPtr frame; - hr = decoder->GetFrame( 0, frame.GetAddressOf() ); - if ( FAILED(hr) ) + hr = decoder->GetFrame(0, frame.GetAddressOf()); + if (FAILED(hr)) return hr; // Get metadata TexMetadata mdata; - WICPixelFormatGUID convertGUID = {0}; - hr = _DecodeMetadata( flags, iswic2, decoder.Get(), frame.Get(), mdata, &convertGUID, getMQR ); - if ( FAILED(hr) ) + WICPixelFormatGUID convertGUID = { 0 }; + hr = DecodeMetadata(flags, iswic2, decoder.Get(), frame.Get(), mdata, &convertGUID, getMQR); + if (FAILED(hr)) return hr; - if ( (mdata.arraySize > 1) && (flags & WIC_FLAGS_ALL_FRAMES) ) + if ((mdata.arraySize > 1) && (flags & WIC_FLAGS_ALL_FRAMES)) { - hr = _DecodeMultiframe( flags, mdata, decoder.Get(), image ); + hr = DecodeMultiframe(flags, mdata, decoder.Get(), image); } else { - hr = _DecodeSingleFrame( flags, mdata, convertGUID, frame.Get(), image ); + hr = DecodeSingleFrame(flags, mdata, convertGUID, frame.Get(), image); } - if ( FAILED(hr) ) + if (FAILED(hr)) { image.Release(); return hr; } - if ( metadata ) - memcpy( metadata, &mdata, sizeof(TexMetadata) ); + if (metadata) + memcpy(metadata, &mdata, sizeof(TexMetadata)); return S_OK; } @@ -1062,98 +1114,109 @@ HRESULT LoadFromWICFile( LPCWSTR szFile, DWORD flags, TexMetadata* metadata, Scr // Save a WIC-supported file to memory //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT SaveToWICMemory( const Image& image, DWORD flags, REFGUID containerFormat, Blob& blob, - const GUID* targetFormat, std::function setCustomProps ) +HRESULT DirectX::SaveToWICMemory( + const Image& image, + DWORD flags, + REFGUID containerFormat, + Blob& blob, + const GUID* targetFormat, + std::function setCustomProps) { - if ( !image.pixels ) + if (!image.pixels) return E_POINTER; blob.Release(); ComPtr stream; - HRESULT hr = CreateMemoryStream( stream.GetAddressOf() ); - if ( FAILED(hr) ) + HRESULT hr = CreateMemoryStream(stream.GetAddressOf()); + if (FAILED(hr)) return hr; - hr = _EncodeSingleFrame( image, flags, containerFormat, stream.Get(), targetFormat, setCustomProps ); - if ( FAILED(hr) ) + hr = EncodeSingleFrame(image, flags, containerFormat, stream.Get(), targetFormat, setCustomProps); + if (FAILED(hr)) return hr; // Copy stream data into blob STATSTG stat; - hr = stream->Stat( &stat, STATFLAG_NONAME ); - if ( FAILED(hr) ) + hr = stream->Stat(&stat, STATFLAG_NONAME); + if (FAILED(hr)) return hr; - if ( stat.cbSize.HighPart > 0 ) - return HRESULT_FROM_WIN32( ERROR_FILE_TOO_LARGE ); + if (stat.cbSize.HighPart > 0) + return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE); - hr = blob.Initialize( stat.cbSize.LowPart ); - if ( FAILED(hr) ) + hr = blob.Initialize(stat.cbSize.LowPart); + if (FAILED(hr)) return hr; LARGE_INTEGER li = { 0 }; - hr = stream->Seek( li, STREAM_SEEK_SET, 0 ); - if ( FAILED(hr) ) + hr = stream->Seek(li, STREAM_SEEK_SET, 0); + if (FAILED(hr)) return hr; DWORD bytesRead; - hr = stream->Read( blob.GetBufferPointer(), static_cast( blob.GetBufferSize() ), &bytesRead ); - if ( FAILED(hr) ) + hr = stream->Read(blob.GetBufferPointer(), static_cast(blob.GetBufferSize()), &bytesRead); + if (FAILED(hr)) return hr; - if ( bytesRead != blob.GetBufferSize() ) + if (bytesRead != blob.GetBufferSize()) return E_FAIL; return S_OK; } _Use_decl_annotations_ -HRESULT SaveToWICMemory( const Image* images, size_t nimages, DWORD flags, REFGUID containerFormat, Blob& blob, - const GUID* targetFormat, std::function setCustomProps ) +HRESULT DirectX::SaveToWICMemory( + const Image* images, + size_t nimages, + DWORD flags, + REFGUID containerFormat, + Blob& blob, + const GUID* targetFormat, + std::function setCustomProps) { - if ( !images || nimages == 0 ) + if (!images || nimages == 0) return E_INVALIDARG; blob.Release(); ComPtr stream; - HRESULT hr = CreateMemoryStream( stream.GetAddressOf() ); - if ( FAILED(hr) ) + HRESULT hr = CreateMemoryStream(stream.GetAddressOf()); + if (FAILED(hr)) return hr; - if ( nimages > 1 ) - hr = _EncodeMultiframe( images, nimages, flags, containerFormat, stream.Get(), targetFormat, setCustomProps ); + if (nimages > 1) + hr = EncodeMultiframe(images, nimages, flags, containerFormat, stream.Get(), targetFormat, setCustomProps); else - hr = _EncodeSingleFrame( images[0], flags, containerFormat, stream.Get(), targetFormat, setCustomProps ); + hr = EncodeSingleFrame(images[0], flags, containerFormat, stream.Get(), targetFormat, setCustomProps); - if ( FAILED(hr) ) + if (FAILED(hr)) return hr; // Copy stream data into blob STATSTG stat; - hr = stream->Stat( &stat, STATFLAG_NONAME ); - if ( FAILED(hr) ) + hr = stream->Stat(&stat, STATFLAG_NONAME); + if (FAILED(hr)) return hr; - if ( stat.cbSize.HighPart > 0 ) - return HRESULT_FROM_WIN32( ERROR_FILE_TOO_LARGE ); + if (stat.cbSize.HighPart > 0) + return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE); - hr = blob.Initialize( stat.cbSize.LowPart ); - if ( FAILED(hr) ) + hr = blob.Initialize(stat.cbSize.LowPart); + if (FAILED(hr)) return hr; LARGE_INTEGER li = { 0 }; - hr = stream->Seek( li, STREAM_SEEK_SET, 0 ); - if ( FAILED(hr) ) + hr = stream->Seek(li, STREAM_SEEK_SET, 0); + if (FAILED(hr)) return hr; DWORD bytesRead; - hr = stream->Read( blob.GetBufferPointer(), static_cast( blob.GetBufferSize() ), &bytesRead ); - if ( FAILED(hr) ) + hr = stream->Read(blob.GetBufferPointer(), static_cast(blob.GetBufferSize()), &bytesRead); + if (FAILED(hr)) return hr; - if ( bytesRead != blob.GetBufferSize() ) + if (bytesRead != blob.GetBufferSize()) return E_FAIL; return S_OK; @@ -1164,34 +1227,39 @@ HRESULT SaveToWICMemory( const Image* images, size_t nimages, DWORD flags, REFGU // Save a WIC-supported file to disk //------------------------------------------------------------------------------------- _Use_decl_annotations_ -HRESULT SaveToWICFile( const Image& image, DWORD flags, REFGUID containerFormat, LPCWSTR szFile, - const GUID* targetFormat, std::function setCustomProps ) +HRESULT DirectX::SaveToWICFile( + const Image& image, + DWORD flags, + REFGUID containerFormat, + const wchar_t* szFile, + const GUID* targetFormat, + std::function setCustomProps) { - if ( !szFile ) + if (!szFile) return E_INVALIDARG; - if ( !image.pixels ) + if (!image.pixels) return E_POINTER; bool iswic2 = false; IWICImagingFactory* pWIC = GetWICFactory(iswic2); - if ( !pWIC ) + if (!pWIC) return E_NOINTERFACE; ComPtr stream; - HRESULT hr = pWIC->CreateStream( stream.GetAddressOf() ); - if ( FAILED(hr) ) + HRESULT hr = pWIC->CreateStream(stream.GetAddressOf()); + if (FAILED(hr)) return hr; - hr = stream->InitializeFromFilename( szFile, GENERIC_WRITE ); - if ( FAILED(hr) ) + hr = stream->InitializeFromFilename(szFile, GENERIC_WRITE); + if (FAILED(hr)) return hr; - hr = _EncodeSingleFrame( image, flags, containerFormat, stream.Get(), targetFormat, setCustomProps ); - if ( FAILED(hr) ) + hr = EncodeSingleFrame(image, flags, containerFormat, stream.Get(), targetFormat, setCustomProps); + if (FAILED(hr)) { stream.Reset(); - DeleteFileW( szFile ); + DeleteFileW(szFile); return hr; } @@ -1199,39 +1267,43 @@ HRESULT SaveToWICFile( const Image& image, DWORD flags, REFGUID containerFormat, } _Use_decl_annotations_ -HRESULT SaveToWICFile( const Image* images, size_t nimages, DWORD flags, REFGUID containerFormat, LPCWSTR szFile, const GUID* targetFormat, - std::function setCustomProps ) +HRESULT DirectX::SaveToWICFile( + const Image* images, + size_t nimages, + DWORD flags, + REFGUID containerFormat, + const wchar_t* szFile, + const GUID* targetFormat, + std::function setCustomProps) { - if ( !szFile || !images || nimages == 0 ) + if (!szFile || !images || nimages == 0) return E_INVALIDARG; bool iswic2 = false; IWICImagingFactory* pWIC = GetWICFactory(iswic2); - if ( !pWIC ) + if (!pWIC) return E_NOINTERFACE; ComPtr stream; - HRESULT hr = pWIC->CreateStream( stream.GetAddressOf() ); - if ( FAILED(hr) ) + HRESULT hr = pWIC->CreateStream(stream.GetAddressOf()); + if (FAILED(hr)) return hr; - hr = stream->InitializeFromFilename( szFile, GENERIC_WRITE ); - if ( FAILED(hr) ) + hr = stream->InitializeFromFilename(szFile, GENERIC_WRITE); + if (FAILED(hr)) return hr; - if ( nimages > 1 ) - hr = _EncodeMultiframe( images, nimages, flags, containerFormat, stream.Get(), targetFormat, setCustomProps ); + if (nimages > 1) + hr = EncodeMultiframe(images, nimages, flags, containerFormat, stream.Get(), targetFormat, setCustomProps); else - hr = _EncodeSingleFrame( images[0], flags, containerFormat, stream.Get(), targetFormat, setCustomProps ); + hr = EncodeSingleFrame(images[0], flags, containerFormat, stream.Get(), targetFormat, setCustomProps); - if ( FAILED(hr) ) + if (FAILED(hr)) { stream.Reset(); - DeleteFileW( szFile ); + DeleteFileW(szFile); return hr; } return S_OK; } - -}; // namespace diff --git a/DirectXTex/Filters.h b/DirectXTex/Filters.h index c65eb77..0741a9a 100644 --- a/DirectXTex/Filters.h +++ b/DirectXTex/Filters.h @@ -63,36 +63,36 @@ struct LinearFilter float weight1; }; -inline void _CreateLinearFilter( _In_ size_t source, _In_ size_t dest, _In_ bool wrap, _Out_writes_(dest) LinearFilter* lf ) +inline void _CreateLinearFilter(_In_ size_t source, _In_ size_t dest, _In_ bool wrap, _Out_writes_(dest) LinearFilter* lf) { - assert( source > 0 ); - assert( dest > 0 ); - assert( lf != 0 ); + assert(source > 0); + assert(dest > 0); + assert(lf != 0); float scale = float(source) / float(dest); // Mirror is the same case as clamp for linear - for( size_t u = 0; u < dest; ++u ) + for (size_t u = 0; u < dest; ++u) { - float srcB = ( float(u) + 0.5f ) * scale + 0.5f; + float srcB = (float(u) + 0.5f) * scale + 0.5f; ptrdiff_t isrcB = ptrdiff_t(srcB); ptrdiff_t isrcA = isrcB - 1; - - if ( isrcA < 0 ) + + if (isrcA < 0) { - isrcA = ( wrap ) ? ( source - 1) : 0; + isrcA = (wrap) ? (source - 1) : 0; } - if ( size_t(isrcB) >= source ) + if (size_t(isrcB) >= source) { - isrcB = ( wrap ) ? 0 : ( source - 1); + isrcB = (wrap) ? 0 : (source - 1); } float weight = 1.0f + float(isrcB) - srcB; - auto& entry = lf[ u ]; + auto& entry = lf[u]; entry.u0 = size_t(isrcA); entry.weight0 = weight; @@ -120,34 +120,34 @@ XMGLOBALCONST XMVECTORF32 g_cubicThird = { 1.f/3.f, 1.f/3.f, 1.f/3.f, 1.f/3.f }; XMGLOBALCONST XMVECTORF32 g_cubicSixth = { 1.f/6.f, 1.f/6.f, 1.f/6.f, 1.f/6.f }; XMGLOBALCONST XMVECTORF32 g_cubicHalf = { 1.f/2.f, 1.f/2.f, 1.f/2.f, 1.f/2.f }; -inline ptrdiff_t bounduvw( ptrdiff_t u, ptrdiff_t maxu, bool wrap, bool mirror ) +inline ptrdiff_t bounduvw(ptrdiff_t u, ptrdiff_t maxu, bool wrap, bool mirror) { - if ( wrap ) + if (wrap) { - if ( u < 0 ) + if (u < 0) { u = maxu + u + 1; } - else if ( u > maxu ) + else if (u > maxu) { u = u - maxu - 1; } } - else if ( mirror ) + else if (mirror) { - if ( u < 0 ) + if (u < 0) { - u = ( -u ) - 1; + u = (-u) - 1; } - else if ( u > maxu ) + else if (u > maxu) { u = maxu - (u - maxu - 1); } } // Handles clamp, but also a safety factor for degenerate images for wrap/mirror - u = std::min( u, maxu ); - u = std::max( u, 0 ); + u = std::min(u, maxu); + u = std::max(u, 0); return u; } @@ -161,24 +161,24 @@ struct CubicFilter float x; }; -inline void _CreateCubicFilter( _In_ size_t source, _In_ size_t dest, _In_ bool wrap, _In_ bool mirror, _Out_writes_(dest) CubicFilter* cf ) +inline void _CreateCubicFilter(_In_ size_t source, _In_ size_t dest, _In_ bool wrap, _In_ bool mirror, _Out_writes_(dest) CubicFilter* cf) { - assert( source > 0 ); - assert( dest > 0 ); - assert( cf != 0 ); + assert(source > 0); + assert(dest > 0); + assert(cf != 0); float scale = float(source) / float(dest); - for( size_t u = 0; u < dest; ++u ) + for (size_t u = 0; u < dest; ++u) { - float srcB = ( float(u) + 0.5f ) * scale - 0.5f; + float srcB = (float(u) + 0.5f) * scale - 0.5f; - ptrdiff_t isrcB = bounduvw( ptrdiff_t(srcB), source - 1, wrap, mirror ); - ptrdiff_t isrcA = bounduvw( isrcB - 1, source - 1, wrap, mirror ); - ptrdiff_t isrcC = bounduvw( isrcB + 1, source - 1, wrap, mirror ); - ptrdiff_t isrcD = bounduvw( isrcB + 2, source - 1, wrap, mirror ); + ptrdiff_t isrcB = bounduvw(ptrdiff_t(srcB), source - 1, wrap, mirror); + ptrdiff_t isrcA = bounduvw(isrcB - 1, source - 1, wrap, mirror); + ptrdiff_t isrcC = bounduvw(isrcB + 1, source - 1, wrap, mirror); + ptrdiff_t isrcD = bounduvw(isrcB + 2, source - 1, wrap, mirror); - auto& entry = cf[ u ]; + auto& entry = cf[u]; entry.u0 = size_t(isrcA); entry.u1 = size_t(isrcB); entry.u2 = size_t(isrcC); @@ -246,10 +246,10 @@ namespace TriangleFilter static const float TF_EPSILON = 0.00001f; - inline HRESULT _Create( _In_ size_t source, _In_ size_t dest, _In_ bool wrap, _Inout_ std::unique_ptr& tf ) + inline HRESULT _Create(_In_ size_t source, _In_ size_t dest, _In_ bool wrap, _Inout_ std::unique_ptr& tf) { - assert( source > 0 ); - assert( dest > 0 ); + assert(source > 0); + assert(dest > 0); float scale = float(dest) / float(source); float scaleInv = 0.5f / scale; @@ -258,109 +258,109 @@ namespace TriangleFilter size_t totalSize = TF_FILTER_SIZE + TF_FROM_SIZE + TF_TO_SIZE; float repeat = (wrap) ? 1.f : 0.f; - for( size_t u = 0; u < source; ++u ) + for (size_t u = 0; u < source; ++u) { float src = float(u) - 0.5f; float destMin = src * scale; float destMax = destMin + scale; - totalSize += TF_FROM_SIZE + TF_TO_SIZE + size_t( destMax - destMin + repeat + 1.f ) * TF_TO_SIZE * 2; + totalSize += TF_FROM_SIZE + TF_TO_SIZE + size_t(destMax - destMin + repeat + 1.f) * TF_TO_SIZE * 2; } uint8_t* pFilter = nullptr; - if ( tf ) + if (tf) { // See if existing filter memory block is large enough to reuse - if ( tf->totalSize >= totalSize ) + if (tf->totalSize >= totalSize) { - pFilter = reinterpret_cast( tf.get() ); + pFilter = reinterpret_cast(tf.get()); } else { // Need to reallocate filter memory block - tf.reset( nullptr ); + tf.reset(nullptr); } } - if ( !tf ) + if (!tf) { // Allocate filter memory block - pFilter = new (std::nothrow) uint8_t[ totalSize ]; - if ( !pFilter ) + pFilter = new (std::nothrow) uint8_t[totalSize]; + if (!pFilter) return E_OUTOFMEMORY; - tf.reset( reinterpret_cast( pFilter ) ); + tf.reset(reinterpret_cast(pFilter)); tf->totalSize = totalSize; } - assert( pFilter != 0 ); + assert(pFilter != 0); // Filter setup size_t sizeInBytes = TF_FILTER_SIZE; size_t accumU = 0; float accumWeight = 0.f; - for( size_t u = 0; u < source; ++u ) + for (size_t u = 0; u < source; ++u) { // Setup from entry size_t sizeFrom = sizeInBytes; - auto pFrom = reinterpret_cast( pFilter + sizeInBytes ); + auto pFrom = reinterpret_cast(pFilter + sizeInBytes); sizeInBytes += TF_FROM_SIZE; - if ( sizeInBytes > totalSize ) + if (sizeInBytes > totalSize) return E_FAIL; size_t toCount = 0; // Perform two passes to capture the influences from both sides - for( size_t j = 0; j < 2; ++j ) + for (size_t j = 0; j < 2; ++j) { - float src = float( u + j ) - 0.5f; + float src = float(u + j) - 0.5f; float destMin = src * scale; float destMax = destMin + scale; - if ( !wrap ) + if (!wrap) { // Clamp - if ( destMin < 0.f ) + if (destMin < 0.f) destMin = 0.f; - if ( destMax > float(dest) ) + if (destMax > float(dest)) destMax = float(dest); } - for( auto k = static_cast( floorf( destMin ) ); float(k) < destMax; ++k ) + for (auto k = static_cast(floorf(destMin)); float(k) < destMax; ++k) { float d0 = float(k); float d1 = d0 + 1.f; size_t u0; - if ( k < 0 ) + if (k < 0) { // Handle wrap - u0 = size_t( k + ptrdiff_t(dest) ); + u0 = size_t(k + ptrdiff_t(dest)); } - else if ( k >= ptrdiff_t(dest) ) + else if (k >= ptrdiff_t(dest)) { // Handle wrap - u0 = size_t( k - ptrdiff_t(dest) ); + u0 = size_t(k - ptrdiff_t(dest)); } else { - u0 = size_t( k ); + u0 = size_t(k); } // Save previous accumulated weight (if any) - if ( u0 != accumU ) + if (u0 != accumU) { - if ( accumWeight > TF_EPSILON ) + if (accumWeight > TF_EPSILON) { - auto pTo = reinterpret_cast( pFilter + sizeInBytes ); + auto pTo = reinterpret_cast(pFilter + sizeInBytes); sizeInBytes += TF_TO_SIZE; ++toCount; - if ( sizeInBytes > totalSize ) + if (sizeInBytes > totalSize) return E_FAIL; pTo->u = accumU; @@ -372,33 +372,33 @@ namespace TriangleFilter } // Clip destination - if ( d0 < destMin ) + if (d0 < destMin) d0 = destMin; - if ( d1 > destMax ) + if (d1 > destMax) d1 = destMax; // Calculate average weight over destination pixel float weight; - if ( !wrap && src < 0.f ) + if (!wrap && src < 0.f) weight = 1.f; - else if ( !wrap && ( ( src + 1.f ) >= float(source) ) ) + else if (!wrap && ((src + 1.f) >= float(source))) weight = 0.f; else weight = (d0 + d1) * scaleInv - src; - accumWeight += (d1 - d0) * ( j ? (1.f - weight) : weight ); + accumWeight += (d1 - d0) * (j ? (1.f - weight) : weight); } } // Store accumulated weight - if ( accumWeight > TF_EPSILON ) + if (accumWeight > TF_EPSILON) { - auto pTo = reinterpret_cast( pFilter + sizeInBytes ); + auto pTo = reinterpret_cast(pFilter + sizeInBytes); sizeInBytes += TF_TO_SIZE; ++toCount; - if ( sizeInBytes > totalSize ) + if (sizeInBytes > totalSize) return E_FAIL; pTo->u = accumU; @@ -417,6 +417,6 @@ namespace TriangleFilter return S_OK; } -}; // namespace +}; // namespace TriangleFilter -}; // namespace \ No newline at end of file +}; // namespace DirectX \ No newline at end of file diff --git a/ScreenGrab/ScreenGrab.cpp b/ScreenGrab/ScreenGrab.cpp index e3b94db..3dbf652 100644 --- a/ScreenGrab/ScreenGrab.cpp +++ b/ScreenGrab/ScreenGrab.cpp @@ -229,7 +229,7 @@ namespace class auto_delete_file_wic { public: - auto_delete_file_wic(ComPtr& hFile, LPCWSTR szFile) : m_handle(hFile), m_filename(szFile) {} + auto_delete_file_wic(ComPtr& hFile, const wchar_t* szFile) : m_handle(hFile), m_filename(szFile) {} ~auto_delete_file_wic() { if (m_filename) @@ -242,7 +242,7 @@ namespace void clear() { m_filename = 0; } private: - LPCWSTR m_filename; + const wchar_t* m_filename; ComPtr& m_handle; auto_delete_file_wic(const auto_delete_file_wic&) = delete; @@ -705,7 +705,7 @@ namespace IWICImagingFactory* factory = nullptr; InitOnceExecuteOnce(&s_initOnce, - [](PINIT_ONCE, PVOID, PVOID *factory) -> BOOL + [](PINIT_ONCE, PVOID, LPVOID *factory) -> BOOL { #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE) HRESULT hr = CoCreateInstance( @@ -751,7 +751,7 @@ namespace //-------------------------------------------------------------------------------------- HRESULT DirectX::SaveDDSTextureToFile( _In_ ID3D11DeviceContext* pContext, _In_ ID3D11Resource* pSource, - _In_z_ LPCWSTR fileName ) + _In_z_ const wchar_t* fileName ) { if ( !fileName ) return E_INVALIDARG; @@ -764,9 +764,9 @@ HRESULT DirectX::SaveDDSTextureToFile( _In_ ID3D11DeviceContext* pContext, // Create file #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) - ScopedHandle hFile( safe_handle( CreateFile2( fileName, GENERIC_WRITE | DELETE, 0, CREATE_ALWAYS, 0 ) ) ); + ScopedHandle hFile( safe_handle( CreateFile2( fileName, GENERIC_WRITE | DELETE, 0, CREATE_ALWAYS, nullptr ) ) ); #else - ScopedHandle hFile( safe_handle( CreateFileW( fileName, GENERIC_WRITE | DELETE, 0, 0, CREATE_ALWAYS, 0, 0 ) ) ); + ScopedHandle hFile( safe_handle( CreateFileW( fileName, GENERIC_WRITE | DELETE, 0, nullptr, CREATE_ALWAYS, 0, nullptr ) ) ); #endif if ( !hFile ) return HRESULT_FROM_WIN32( GetLastError() ); @@ -912,7 +912,7 @@ HRESULT DirectX::SaveDDSTextureToFile( _In_ ID3D11DeviceContext* pContext, HRESULT DirectX::SaveWICTextureToFile( _In_ ID3D11DeviceContext* pContext, _In_ ID3D11Resource* pSource, _In_ REFGUID guidContainerFormat, - _In_z_ LPCWSTR fileName, + _In_z_ const wchar_t* fileName, _In_opt_ const GUID* targetFormat, _In_opt_ std::function setCustomProps ) { diff --git a/ScreenGrab/ScreenGrab.h b/ScreenGrab/ScreenGrab.h index d643073..f2e7025 100644 --- a/ScreenGrab/ScreenGrab.h +++ b/ScreenGrab/ScreenGrab.h @@ -32,12 +32,12 @@ namespace DirectX { HRESULT SaveDDSTextureToFile( _In_ ID3D11DeviceContext* pContext, _In_ ID3D11Resource* pSource, - _In_z_ LPCWSTR fileName ); + _In_z_ const wchar_t* fileName ); HRESULT SaveWICTextureToFile( _In_ ID3D11DeviceContext* pContext, _In_ ID3D11Resource* pSource, _In_ REFGUID guidContainerFormat, - _In_z_ LPCWSTR fileName, + _In_z_ const wchar_t* fileName, _In_opt_ const GUID* targetFormat = nullptr, _In_opt_ std::function setCustomProps = nullptr ); } \ No newline at end of file diff --git a/ScreenGrab/ScreenGrab12.cpp b/ScreenGrab/ScreenGrab12.cpp index 27b019a..1478a89 100644 --- a/ScreenGrab/ScreenGrab12.cpp +++ b/ScreenGrab/ScreenGrab12.cpp @@ -839,11 +839,7 @@ HRESULT DirectX::SaveDDSTextureToFile( ID3D12CommandQueue* pCommandQ, return hr; // Create file -#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) - ScopedHandle hFile( safe_handle( CreateFile2( fileName, GENERIC_WRITE, 0, CREATE_ALWAYS, 0 ) ) ); -#else - ScopedHandle hFile( safe_handle( CreateFileW( fileName, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0 ) ) ); -#endif + ScopedHandle hFile( safe_handle( CreateFile2( fileName, GENERIC_WRITE, 0, CREATE_ALWAYS, nullptr ) ) ); if ( !hFile ) return HRESULT_FROM_WIN32( GetLastError() ); @@ -972,13 +968,13 @@ HRESULT DirectX::SaveDDSTextureToFile( ID3D12CommandQueue* pCommandQ, // Write header & pixels DWORD bytesWritten; - if ( !WriteFile( hFile.get(), fileHeader, static_cast( headerSize ), &bytesWritten, 0 ) ) + if ( !WriteFile( hFile.get(), fileHeader, static_cast( headerSize ), &bytesWritten, nullptr ) ) return HRESULT_FROM_WIN32( GetLastError() ); if ( bytesWritten != headerSize ) return E_FAIL; - if ( !WriteFile( hFile.get(), pixels.get(), static_cast( slicePitch ), &bytesWritten, 0 ) ) + if ( !WriteFile( hFile.get(), pixels.get(), static_cast( slicePitch ), &bytesWritten, nullptr ) ) return HRESULT_FROM_WIN32( GetLastError() ); if ( bytesWritten != slicePitch ) diff --git a/WICTextureLoader/WICTextureLoader.h b/WICTextureLoader/WICTextureLoader.h index 2b0340c..9b5ac4f 100644 --- a/WICTextureLoader/WICTextureLoader.h +++ b/WICTextureLoader/WICTextureLoader.h @@ -34,90 +34,98 @@ namespace DirectX { // Standard version - HRESULT CreateWICTextureFromMemory( _In_ ID3D11Device* d3dDevice, - _In_reads_bytes_(wicDataSize) const uint8_t* wicData, - _In_ size_t wicDataSize, - _Out_opt_ ID3D11Resource** texture, - _Out_opt_ ID3D11ShaderResourceView** textureView, - _In_ size_t maxsize = 0 - ); + HRESULT CreateWICTextureFromMemory( + _In_ ID3D11Device* d3dDevice, + _In_reads_bytes_(wicDataSize) const uint8_t* wicData, + _In_ size_t wicDataSize, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize = 0 + ); - HRESULT CreateWICTextureFromFile( _In_ ID3D11Device* d3dDevice, - _In_z_ const wchar_t* szFileName, - _Out_opt_ ID3D11Resource** texture, - _Out_opt_ ID3D11ShaderResourceView** textureView, - _In_ size_t maxsize = 0 - ); + HRESULT CreateWICTextureFromFile( + _In_ ID3D11Device* d3dDevice, + _In_z_ const wchar_t* szFileName, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize = 0 + ); // Standard version with optional auto-gen mipmap support - HRESULT CreateWICTextureFromMemory( _In_ ID3D11Device* d3dDevice, - _In_opt_ ID3D11DeviceContext* d3dContext, - _In_reads_bytes_(wicDataSize) const uint8_t* wicData, - _In_ size_t wicDataSize, - _Out_opt_ ID3D11Resource** texture, - _Out_opt_ ID3D11ShaderResourceView** textureView, - _In_ size_t maxsize = 0 - ); + HRESULT CreateWICTextureFromMemory( + _In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, + _In_reads_bytes_(wicDataSize) const uint8_t* wicData, + _In_ size_t wicDataSize, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize = 0 + ); - HRESULT CreateWICTextureFromFile( _In_ ID3D11Device* d3dDevice, - _In_opt_ ID3D11DeviceContext* d3dContext, - _In_z_ const wchar_t* szFileName, - _Out_opt_ ID3D11Resource** texture, - _Out_opt_ ID3D11ShaderResourceView** textureView, - _In_ size_t maxsize = 0 - ); + HRESULT CreateWICTextureFromFile( + _In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, + _In_z_ const wchar_t* szFileName, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize = 0 + ); // Extended version - HRESULT CreateWICTextureFromMemoryEx( _In_ ID3D11Device* d3dDevice, - _In_reads_bytes_(wicDataSize) const uint8_t* wicData, - _In_ size_t wicDataSize, - _In_ size_t maxsize, - _In_ D3D11_USAGE usage, - _In_ unsigned int bindFlags, - _In_ unsigned int cpuAccessFlags, - _In_ unsigned int miscFlags, - _In_ bool forceSRGB, - _Out_opt_ ID3D11Resource** texture, - _Out_opt_ ID3D11ShaderResourceView** textureView - ); + HRESULT CreateWICTextureFromMemoryEx( + _In_ ID3D11Device* d3dDevice, + _In_reads_bytes_(wicDataSize) const uint8_t* wicData, + _In_ size_t wicDataSize, + _In_ size_t maxsize, + D3D11_USAGE usage, + _In_ unsigned int bindFlags, + _In_ unsigned int cpuAccessFlags, + _In_ unsigned int miscFlags, + _In_ bool forceSRGB, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView + ); - HRESULT CreateWICTextureFromFileEx( _In_ ID3D11Device* d3dDevice, - _In_z_ const wchar_t* szFileName, - _In_ size_t maxsize, - _In_ D3D11_USAGE usage, - _In_ unsigned int bindFlags, - _In_ unsigned int cpuAccessFlags, - _In_ unsigned int miscFlags, - _In_ bool forceSRGB, - _Out_opt_ ID3D11Resource** texture, - _Out_opt_ ID3D11ShaderResourceView** textureView - ); + HRESULT CreateWICTextureFromFileEx( + _In_ ID3D11Device* d3dDevice, + _In_z_ const wchar_t* szFileName, + _In_ size_t maxsize, + _In_ D3D11_USAGE usage, + _In_ unsigned int bindFlags, + _In_ unsigned int cpuAccessFlags, + _In_ unsigned int miscFlags, + _In_ bool forceSRGB, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView + ); // Extended version with optional auto-gen mipmap support - HRESULT CreateWICTextureFromMemoryEx( _In_ ID3D11Device* d3dDevice, - _In_opt_ ID3D11DeviceContext* d3dContext, - _In_reads_bytes_(wicDataSize) const uint8_t* wicData, - _In_ size_t wicDataSize, - _In_ size_t maxsize, - _In_ D3D11_USAGE usage, - _In_ unsigned int bindFlags, - _In_ unsigned int cpuAccessFlags, - _In_ unsigned int miscFlags, - _In_ bool forceSRGB, - _Out_opt_ ID3D11Resource** texture, - _Out_opt_ ID3D11ShaderResourceView** textureView - ); + HRESULT CreateWICTextureFromMemoryEx( + _In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, + _In_reads_bytes_(wicDataSize) const uint8_t* wicData, + _In_ size_t wicDataSize, + _In_ size_t maxsize, + _In_ D3D11_USAGE usage, + _In_ unsigned int bindFlags, + _In_ unsigned int cpuAccessFlags, + _In_ unsigned int miscFlags, + _In_ bool forceSRGB, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView + ); - HRESULT CreateWICTextureFromFileEx( _In_ ID3D11Device* d3dDevice, - _In_opt_ ID3D11DeviceContext* d3dContext, - _In_z_ const wchar_t* szFileName, - _In_ size_t maxsize, - _In_ D3D11_USAGE usage, - _In_ unsigned int bindFlags, - _In_ unsigned int cpuAccessFlags, - _In_ unsigned int miscFlags, - _In_ bool forceSRGB, - _Out_opt_ ID3D11Resource** texture, - _Out_opt_ ID3D11ShaderResourceView** textureView - ); + HRESULT CreateWICTextureFromFileEx( + _In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, + _In_z_ const wchar_t* szFileName, + _In_ size_t maxsize, + _In_ D3D11_USAGE usage, + _In_ unsigned int bindFlags, + _In_ unsigned int cpuAccessFlags, + _In_ unsigned int miscFlags, + _In_ bool forceSRGB, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView + ); } \ No newline at end of file