//=============================================================================== // Copyright (c) 2007-2016 Advanced Micro Devices, Inc. All rights reserved. // Copyright (c) 2004-2006 ATI Technologies Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files(the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and / or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions : // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // File Name: Compress.cpp // Description: A library to compress/decompress textures // // Revisions // Apr 2014 - Refactored Library // Code clean to support MSV 2010 and up ////////////////////////////////////////////////////////////////////////////// #include "common.h" #include "compressonator.h" #include "compress.h" #include "atiformats.h" #include #include #ifdef _WIN32 #include "windows.h" #include "sysinfoapi.h" #endif CMP_INT CMP_GetNumberOfProcessors() { #ifndef _WIN32 // return sysconf(_SC_NPROCESSORS_ONLN); return std::thread::hardware_concurrency(); #else // Figure out how many cores there are on this machine SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); return (sysinfo.dwNumberOfProcessors); #endif } CodecType GetCodecType(CMP_FORMAT format) { switch(format) { case CMP_FORMAT_RGBA_1010102: case CMP_FORMAT_ARGB_2101010: return CT_None; case CMP_FORMAT_RGBA_8888: return CT_None; case CMP_FORMAT_BGRA_8888: return CT_None; case CMP_FORMAT_RGBA_8888_S: case CMP_FORMAT_ARGB_8888: return CT_None; case CMP_FORMAT_BGR_888: return CT_None; case CMP_FORMAT_RGB_888: return CT_None; case CMP_FORMAT_RG_8: return CT_None; case CMP_FORMAT_R_8: return CT_None; case CMP_FORMAT_ARGB_16: return CT_None; case CMP_FORMAT_RG_16: return CT_None; case CMP_FORMAT_R_16: return CT_None; case CMP_FORMAT_ABGR_16F: case CMP_FORMAT_ARGB_16F: case CMP_FORMAT_RGBA_16F: return CT_None; case CMP_FORMAT_RG_16F: return CT_None; case CMP_FORMAT_R_16F: return CT_None; case CMP_FORMAT_ARGB_32F: case CMP_FORMAT_RGBA_32F: return CT_None; case CMP_FORMAT_RG_32F: return CT_None; case CMP_FORMAT_R_32F: return CT_None; case CMP_FORMAT_RGBE_32F: return CT_None; #ifdef ARGB_32_SUPPORT case CMP_FORMAT_ARGB_32: return CT_None; case CMP_FORMAT_RG_32: return CT_None; case CMP_FORMAT_R_32: return CT_None; #endif // ARGB_32_SUPPORT case CMP_FORMAT_DXT1: return CT_DXT1; case CMP_FORMAT_DXT3: return CT_DXT3; case CMP_FORMAT_DXT5: return CT_DXT5; case CMP_FORMAT_DXT5_xGBR: return CT_DXT5_xGBR; case CMP_FORMAT_DXT5_RxBG: return CT_DXT5_RxBG; case CMP_FORMAT_DXT5_RBxG: return CT_DXT5_RBxG; case CMP_FORMAT_DXT5_xRBG: return CT_DXT5_xRBG; case CMP_FORMAT_DXT5_RGxB: return CT_DXT5_RGxB; case CMP_FORMAT_DXT5_xGxR: return CT_DXT5_xGxR; case CMP_FORMAT_ATI1N: return CT_ATI1N; case CMP_FORMAT_ATI2N: return CT_ATI2N; case CMP_FORMAT_ATI2N_XY: return CT_ATI2N_XY; case CMP_FORMAT_ATI2N_DXT5: return CT_ATI2N_DXT5; case CMP_FORMAT_BC1: return CT_DXT1; case CMP_FORMAT_BC2: return CT_DXT3; case CMP_FORMAT_BC3: return CT_DXT5; case CMP_FORMAT_BC4: return CT_ATI1N; case CMP_FORMAT_BC4_S: return CT_ATI1N_S; case CMP_FORMAT_BC5: return CT_ATI2N_XY; // Red & Green channels case CMP_FORMAT_BC5_S: return CT_ATI2N_XY_S; // Red & Green channels case CMP_FORMAT_BC6H: return CT_BC6H; case CMP_FORMAT_BC6H_SF: return CT_BC6H_SF; case CMP_FORMAT_BC7: return CT_BC7; #if (OPTION_BUILD_ASTC == 1) case CMP_FORMAT_ASTC: return CT_ASTC; #endif case CMP_FORMAT_ATC_RGB: return CT_ATC_RGB; case CMP_FORMAT_ATC_RGBA_Explicit: return CT_ATC_RGBA_Explicit; case CMP_FORMAT_ATC_RGBA_Interpolated: return CT_ATC_RGBA_Interpolated; case CMP_FORMAT_ETC_RGB: return CT_ETC_RGB; case CMP_FORMAT_ETC2_RGB: return CT_ETC2_RGB; case CMP_FORMAT_ETC2_SRGB: return CT_ETC2_SRGB; case CMP_FORMAT_ETC2_RGBA: return CT_ETC2_RGBA; case CMP_FORMAT_ETC2_RGBA1: return CT_ETC2_RGBA1; case CMP_FORMAT_ETC2_SRGBA: return CT_ETC2_SRGBA; case CMP_FORMAT_ETC2_SRGBA1: return CT_ETC2_SRGBA1; #ifdef USE_APC case CMP_FORMAT_APC: return CT_APC; #endif #ifdef USE_GTC case CMP_FORMAT_GTC: return CT_GTC; #endif case CMP_FORMAT_BROTLIG: return CT_BRLG; #ifdef USE_BASIS case CMP_FORMAT_BASIS: return CT_BASIS; #endif case CMP_FORMAT_BINARY: return CT_None; default: return CT_Unknown; } } bool NeedSwizzle(CMP_FORMAT destformat) { // determin of the swizzle flag needs to be turned on! switch (destformat) { case CMP_FORMAT_BC4: case CMP_FORMAT_BC4_S: case CMP_FORMAT_ATI1N: // same as BC4 case CMP_FORMAT_BC5: case CMP_FORMAT_BC5_S: case CMP_FORMAT_ATI2N: // Green & Red Channels case CMP_FORMAT_ATI2N_XY: // same as ATI2N with XY = Red & Green channels case CMP_FORMAT_ATI2N_DXT5: // same as BC5 case CMP_FORMAT_BC1: case CMP_FORMAT_DXT1: // same as BC1 case CMP_FORMAT_BC2: case CMP_FORMAT_DXT3: // same as BC2 case CMP_FORMAT_BC3: case CMP_FORMAT_DXT5: // same as BC3 case CMP_FORMAT_ATC_RGB: case CMP_FORMAT_ATC_RGBA_Explicit: case CMP_FORMAT_ATC_RGBA_Interpolated: return true; break; default: break; } return false; } CMP_ERROR GetError(CodecError err) { switch(err) { case CE_OK: return CMP_OK; case CE_Aborted: return CMP_ABORTED; case CE_Unknown: return CMP_ERR_GENERIC; default: return CMP_ERR_GENERIC; } } CMP_ERROR CheckTexture(const CMP_Texture* pTexture, bool bSource) { if(pTexture == NULL) return (bSource ? CMP_ERR_INVALID_SOURCE_TEXTURE : CMP_ERR_INVALID_DEST_TEXTURE); if (pTexture->pData == NULL) return (bSource ? CMP_ERR_INVALID_SOURCE_TEXTURE : CMP_ERR_INVALID_DEST_TEXTURE); if(pTexture->dwSize != sizeof(CMP_Texture)) return (bSource ? CMP_ERR_INVALID_SOURCE_TEXTURE : CMP_ERR_INVALID_DEST_TEXTURE); if(pTexture->dwWidth <= 0 ) return (bSource ? CMP_ERR_INVALID_SOURCE_TEXTURE : CMP_ERR_INVALID_DEST_TEXTURE); if(pTexture->dwHeight <= 0 ) return (bSource ? CMP_ERR_INVALID_SOURCE_TEXTURE : CMP_ERR_INVALID_DEST_TEXTURE); if (!CMP_IsValidFormat(pTexture->format)) return (bSource ? CMP_ERR_UNSUPPORTED_SOURCE_FORMAT : CMP_ERR_UNSUPPORTED_DEST_FORMAT); assert((pTexture->format != CMP_FORMAT_ARGB_8888 && pTexture->format != CMP_FORMAT_ARGB_2101010) || pTexture->dwPitch == 0 || pTexture->dwPitch >= (pTexture->dwWidth*4)); assert((pTexture->format != CMP_FORMAT_RGBA_8888_S && pTexture->format != CMP_FORMAT_ARGB_2101010) || pTexture->dwPitch == 0 || pTexture->dwPitch >= (pTexture->dwWidth * 4)); if((pTexture->format == CMP_FORMAT_ARGB_8888 || pTexture->format == CMP_FORMAT_ARGB_2101010) && pTexture->dwPitch != 0 && pTexture->dwPitch < (pTexture->dwWidth*4)) return (bSource ? CMP_ERR_UNSUPPORTED_SOURCE_FORMAT : CMP_ERR_UNSUPPORTED_DEST_FORMAT); if ((pTexture->format == CMP_FORMAT_RGBA_8888_S || pTexture->format == CMP_FORMAT_ARGB_2101010) && pTexture->dwPitch != 0 && pTexture->dwPitch < (pTexture->dwWidth * 4)) return (bSource ? CMP_ERR_UNSUPPORTED_SOURCE_FORMAT : CMP_ERR_UNSUPPORTED_DEST_FORMAT); CMP_DWORD dwDataSize = CMP_CalculateBufferSize(pTexture); if(pTexture->dwDataSize < dwDataSize) return (bSource ? CMP_ERR_INVALID_SOURCE_TEXTURE : CMP_ERR_INVALID_DEST_TEXTURE); return CMP_OK; } CMP_ERROR CompressTexture(const CMP_Texture* pSourceTexture, CMP_Texture* pDestTexture, const CMP_CompressOptions* pOptions, CMP_Feedback_Proc pFeedbackProc, CodecType destType) { // Compressing CCodec* pCodec = CreateCodec(destType); assert(pCodec); if(pCodec == NULL) return CMP_ERR_UNABLE_TO_INIT_CODEC; CMP_BOOL swizzleSrcBuffer = false; // Have we got valid options ? if(pOptions && pOptions->dwSize == sizeof(CMP_CompressOptions)) { // Set weightings ? if(pOptions->bUseChannelWeighting && (pOptions->fWeightingRed > 0.0 || pOptions->fWeightingGreen > 0.0 || pOptions->fWeightingBlue > 0.0)) { pCodec->SetParameter("UseChannelWeighting", (CMP_DWORD) 1); pCodec->SetParameter("WeightR", pOptions->fWeightingRed > MINIMUM_WEIGHT_VALUE ? (CODECFLOAT) pOptions->fWeightingRed : MINIMUM_WEIGHT_VALUE); pCodec->SetParameter("WeightG", pOptions->fWeightingGreen > MINIMUM_WEIGHT_VALUE ? (CODECFLOAT) pOptions->fWeightingGreen : MINIMUM_WEIGHT_VALUE); pCodec->SetParameter("WeightB", pOptions->fWeightingBlue > MINIMUM_WEIGHT_VALUE ? (CODECFLOAT) pOptions->fWeightingBlue : MINIMUM_WEIGHT_VALUE); } pCodec->SetParameter("UseAdaptiveWeighting", (CMP_DWORD) pOptions->bUseAdaptiveWeighting); pCodec->SetParameter("DXT1UseAlpha", (CMP_DWORD) pOptions->bDXT1UseAlpha); pCodec->SetParameter("AlphaThreshold", (CMP_DWORD) pOptions->nAlphaThreshold); if (pOptions->bUseRefinementSteps) pCodec->SetParameter("RefineSteps", (CMP_DWORD) pOptions->nRefinementSteps); // New override to that set quality if compresion for DXTn & ATInN codecs if (pOptions->fquality != AMD_CODEC_QUALITY_DEFAULT) { pCodec->SetParameter("Quality", (CODECFLOAT)pOptions->fquality); #ifndef _WIN64 if (pOptions->fquality < 0.3) pCodec->SetParameter("CompressionSpeed", (CMP_DWORD)CMP_Speed_SuperFast); else if (pOptions->fquality < 0.6) pCodec->SetParameter("CompressionSpeed", (CMP_DWORD)CMP_Speed_Fast); else #endif pCodec->SetParameter("CompressionSpeed", (CMP_DWORD)CMP_Speed_Normal); } else pCodec->SetParameter("CompressionSpeed", (CMP_DWORD)pOptions->nCompressionSpeed); switch(destType) { case CT_BC7: pCodec->SetParameter("MultiThreading", (CMP_DWORD) !pOptions->bDisableMultiThreading); if (!pOptions->bDisableMultiThreading) pCodec->SetParameter(CodecParameters::NumThreads, (CMP_DWORD) pOptions->dwnumThreads); else pCodec->SetParameter(CodecParameters::NumThreads, (CMP_DWORD) 1); pCodec->SetParameter("ModeMask", (CMP_DWORD) pOptions->dwmodeMask); pCodec->SetParameter("ColourRestrict", (CMP_DWORD) pOptions->brestrictColour); pCodec->SetParameter("AlphaRestrict", (CMP_DWORD) pOptions->brestrictAlpha); pCodec->SetParameter("Quality", (CODECFLOAT) pOptions->fquality); break; #ifdef USE_BASIS case CT_BASIS: #endif #if (OPTION_BUILD_ASTC == 1) case CT_ASTC: pCodec->SetParameter("Quality", (CODECFLOAT)pOptions->fquality); if (!pOptions->bDisableMultiThreading) pCodec->SetParameter(CodecParameters::NumThreads, (CMP_DWORD)pOptions->dwnumThreads); else pCodec->SetParameter(CodecParameters::NumThreads, (CMP_DWORD)1); break; #endif #ifdef USE_APC case CT_APC: #endif #ifdef USE_GTC case CT_GTC: #endif #ifdef USE_LOSSLESS_COMPRESSION case CT_BRLG: { CMP_DWORD pageSize = pOptions->dwPageSize; pCodec->SetParameter(CodecParameters::PageSize, pageSize ? pageSize : AMD_CODEC_PAGE_SIZE_DEFAULT); } break; #endif case CT_BC6H: case CT_BC6H_SF: pCodec->SetParameter("Quality", (CODECFLOAT)pOptions->fquality); if (!pOptions->bDisableMultiThreading) pCodec->SetParameter(CodecParameters::NumThreads, (CMP_DWORD)pOptions->dwnumThreads); else pCodec->SetParameter(CodecParameters::NumThreads, (CMP_DWORD)1); #ifdef _DEBUG // napatel : remove this after // pCodec->SetParameter(CodecParameters::NumThreads, (CMP_DWORD)1); #endif break; } // This will eventually replace the above code for setting codec options if (pOptions->NumCmds > 0) { int maxCmds=pOptions->NumCmds; if (pOptions->NumCmds > AMD_MAX_CMDS) maxCmds = AMD_MAX_CMDS; for (int i=0; iSetParameter(pOptions->CmdSet[i].strCommand, (CMP_CHAR*)pOptions->CmdSet[i].strParameter); } // GPUOpen issue # 59 fix CodecBufferType srcBufferType = GetCodecBufferType(pSourceTexture->format); if (NeedSwizzle(pDestTexture->format)) { switch (srcBufferType) { case CBT_BGRA8888: case CBT_BGR888: case CBT_R8: swizzleSrcBuffer = false; break; default: swizzleSrcBuffer = true; break; } } } CodecBufferType srcBufferType = GetCodecBufferType(pSourceTexture->format); CCodecBuffer* pSrcBuffer = CreateCodecBuffer(srcBufferType, pSourceTexture->nBlockWidth, pSourceTexture->nBlockHeight, pSourceTexture->nBlockDepth, pSourceTexture->dwWidth, pSourceTexture->dwHeight, pSourceTexture->dwPitch, pSourceTexture->pData, pSourceTexture->dwDataSize); CCodecBuffer* pDestBuffer = pCodec->CreateBuffer( pDestTexture->nBlockWidth, pDestTexture->nBlockHeight, pDestTexture->nBlockDepth, pDestTexture->dwWidth, pDestTexture->dwHeight, pDestTexture->dwPitch, pDestTexture->pData, pDestTexture->dwDataSize); assert(pSrcBuffer); assert(pDestBuffer); if(pSrcBuffer == NULL || pDestBuffer == NULL) { SAFE_DELETE(pCodec); SAFE_DELETE(pSrcBuffer); SAFE_DELETE(pDestBuffer); return CMP_ERR_GENERIC; } pSrcBuffer->SetFormat(pSourceTexture->format); pDestBuffer->SetFormat(pDestTexture->format); // GPUOpen issue # 59 and #67 fix pSrcBuffer->m_bSwizzle = swizzleSrcBuffer; DISABLE_FP_EXCEPTIONS; CodecError err = pCodec->Compress(*pSrcBuffer, *pDestBuffer, pFeedbackProc); RESTORE_FP_EXCEPTIONS; pDestTexture->dwDataSize = pDestBuffer->GetDataSize(); SAFE_DELETE(pCodec); SAFE_DELETE(pSrcBuffer); SAFE_DELETE(pDestBuffer); return GetError(err); } #ifdef THREADED_COMPRESS class CATICompressThreadData { public: CATICompressThreadData(); ~CATICompressThreadData(); CCodec* m_pCodec; CCodecBuffer* m_pSrcBuffer; CCodecBuffer* m_pDestBuffer; CMP_Feedback_Proc m_pFeedbackProc; CodecError m_errorCode; }; CATICompressThreadData::CATICompressThreadData() : m_pCodec(NULL), m_pSrcBuffer(NULL), m_pDestBuffer(NULL), m_pFeedbackProc(NULL), m_errorCode( CE_OK ) { } CATICompressThreadData::~CATICompressThreadData() { SAFE_DELETE(m_pCodec); SAFE_DELETE(m_pSrcBuffer); SAFE_DELETE(m_pDestBuffer); } void ThreadedCompressProc(void *lpParameter) { CATICompressThreadData *pThreadData = (CATICompressThreadData*) lpParameter; DISABLE_FP_EXCEPTIONS; CodecError err = pThreadData->m_pCodec->Compress(*pThreadData->m_pSrcBuffer, *pThreadData->m_pDestBuffer, pThreadData->m_pFeedbackProc); RESTORE_FP_EXCEPTIONS; pThreadData->m_errorCode = err; } CMP_ERROR ThreadedCompressTexture(const CMP_Texture* pSourceTexture, CMP_Texture* pDestTexture, const CMP_CompressOptions* pOptions, CMP_Feedback_Proc pFeedbackProc, CodecType destType) { // Note function should not be called for the following Codecs.... if (destType == CT_BC7) return CMP_ABORTED; #ifdef USE_APC if (destType == CT_APC) return CMP_ABORTED; #endif #ifdef USE_GTC if (destType == CT_GTC) return CMP_ABORTED; #endif #ifdef USE_LOSSLESS_COMPRESSION if (destType == CT_BRLG) return CMP_ABORTED; #endif #ifdef USE_BASIS if (destType == CT_BASIS) return CMP_ABORTED; #endif #if (OPTION_BUILD_ASTC == 1) if (destType == CT_ASTC) return CMP_ABORTED; #endif CMP_DWORD dwMaxThreadCount = cmp_minT(f_dwProcessorCount, MAX_THREADS); CMP_DWORD dwLinesRemaining = pDestTexture->dwHeight; CMP_BYTE* pSourceData = pSourceTexture->pData; CMP_BYTE* pDestData = pDestTexture->pData; CMP_BOOL swizzleSrcBuffer = false; #ifdef _DEBUG if ( (pDestTexture->format == CMP_FORMAT_ETC2_RGBA) || (pDestTexture->format == CMP_FORMAT_ETC2_RGBA1) ) dwMaxThreadCount = 1; #endif CATICompressThreadData aThreadData[MAX_THREADS]; std::thread ahThread[MAX_THREADS]; CMP_DWORD dwThreadCount = 0; for(CMP_DWORD dwThread = 0; dwThread < dwMaxThreadCount; dwThread++) { CATICompressThreadData& threadData = aThreadData[dwThread]; // Compressing threadData.m_pCodec = CreateCodec(destType); assert(threadData.m_pCodec); if(threadData.m_pCodec == NULL) return CMP_ERR_UNABLE_TO_INIT_CODEC; // Have we got valid options ? if(pOptions && pOptions->dwSize == sizeof(CMP_CompressOptions)) { // Set weightings ? if(pOptions->bUseChannelWeighting && (pOptions->fWeightingRed > 0.0 || pOptions->fWeightingGreen > 0.0 || pOptions->fWeightingBlue > 0.0)) { threadData.m_pCodec->SetParameter("UseChannelWeighting", (CMP_DWORD) 1); threadData.m_pCodec->SetParameter("WeightR", pOptions->fWeightingRed > MINIMUM_WEIGHT_VALUE ? (CODECFLOAT) pOptions->fWeightingRed : MINIMUM_WEIGHT_VALUE); threadData.m_pCodec->SetParameter("WeightG", pOptions->fWeightingGreen > MINIMUM_WEIGHT_VALUE ? (CODECFLOAT) pOptions->fWeightingGreen : MINIMUM_WEIGHT_VALUE); threadData.m_pCodec->SetParameter("WeightB", pOptions->fWeightingBlue > MINIMUM_WEIGHT_VALUE ? (CODECFLOAT) pOptions->fWeightingBlue : MINIMUM_WEIGHT_VALUE); } threadData.m_pCodec->SetParameter("UseAdaptiveWeighting", (CMP_DWORD) pOptions->bUseAdaptiveWeighting); threadData.m_pCodec->SetParameter("DXT1UseAlpha", (CMP_DWORD) pOptions->bDXT1UseAlpha); threadData.m_pCodec->SetParameter("AlphaThreshold", (CMP_DWORD) pOptions->nAlphaThreshold); threadData.m_pCodec->SetParameter("RefineSteps", (CMP_DWORD) pOptions->nRefinementSteps); threadData.m_pCodec->SetParameter("Quality", (CODECFLOAT)pOptions->fquality); // New override to that set quality if compresion for DXTn & ATInN codecs if (pOptions->fquality != AMD_CODEC_QUALITY_DEFAULT) { if (pOptions->fquality < 0.3) threadData.m_pCodec->SetParameter("CompressionSpeed", (CMP_DWORD)CMP_Speed_SuperFast); else if (pOptions->fquality < 0.6) threadData.m_pCodec->SetParameter("CompressionSpeed", (CMP_DWORD)CMP_Speed_Fast); else threadData.m_pCodec->SetParameter("CompressionSpeed", (CMP_DWORD)CMP_Speed_Normal); } else threadData.m_pCodec->SetParameter("CompressionSpeed", (CMP_DWORD)pOptions->nCompressionSpeed); switch(destType) { case CT_BC6H: // Reserved break; } // This will eventually replace the above code for setting codec options // It is currently implemented with BC6H and can be expanded to other codec if (pOptions->NumCmds > 0) { int maxCmds = pOptions->NumCmds; if (pOptions->NumCmds > AMD_MAX_CMDS) maxCmds = AMD_MAX_CMDS; for (int i = 0; iSetParameter(pOptions->CmdSet[i].strCommand, (CMP_CHAR*)pOptions->CmdSet[i].strParameter); } } CodecBufferType srcBufferType = GetCodecBufferType(pSourceTexture->format); // GPUOpen issue # 59 fix if (NeedSwizzle(pDestTexture->format)) { switch (srcBufferType) { case CBT_BGRA8888: case CBT_BGR888: case CBT_R8: swizzleSrcBuffer = false; break; default: swizzleSrcBuffer = true; break; } } CMP_DWORD dwThreadsRemaining = dwMaxThreadCount - dwThread; CMP_DWORD dwHeight = 0; if(dwThreadsRemaining > 1) { CMP_DWORD dwBlockHeight = threadData.m_pCodec->GetBlockHeight(); dwHeight = dwLinesRemaining / dwThreadsRemaining; dwHeight = cmp_minT(((dwHeight + dwBlockHeight - 1) / dwBlockHeight) * dwBlockHeight, dwLinesRemaining); // Round by block height dwLinesRemaining -= dwHeight; } else dwHeight = dwLinesRemaining; if(dwHeight > 0) { threadData.m_pSrcBuffer = CreateCodecBuffer(srcBufferType, pSourceTexture->nBlockWidth, pSourceTexture->nBlockHeight, pSourceTexture->nBlockDepth, pSourceTexture->dwWidth, dwHeight, pSourceTexture->dwPitch, pSourceData, pSourceTexture->dwDataSize); threadData.m_pSrcBuffer->SetFormat(pSourceTexture->format); threadData.m_pDestBuffer = threadData.m_pCodec->CreateBuffer( pDestTexture->nBlockWidth, pDestTexture->nBlockHeight, pDestTexture->nBlockDepth, pDestTexture->dwWidth, dwHeight, pDestTexture->dwPitch, pDestData, pDestTexture->dwDataSize); threadData.m_pDestBuffer->SetFormat(pDestTexture->format); pSourceData += CalcBufferSize(pSourceTexture->format, pSourceTexture->dwWidth, dwHeight, pSourceTexture->dwPitch, pSourceTexture->nBlockWidth, pSourceTexture->nBlockHeight); pDestData += CalcBufferSize(destType, pDestTexture->dwWidth, dwHeight, pDestTexture->nBlockWidth, pDestTexture->nBlockHeight); assert(threadData.m_pSrcBuffer); assert(threadData.m_pDestBuffer); if(threadData.m_pSrcBuffer == NULL || threadData.m_pDestBuffer == NULL) return CMP_ERR_GENERIC; threadData.m_pSrcBuffer->m_bSwizzle = swizzleSrcBuffer; threadData.m_pFeedbackProc = pFeedbackProc; ahThread[dwThreadCount++] = std::thread(ThreadedCompressProc, &threadData); } } for ( CMP_DWORD dwThread = 0; dwThread < dwThreadCount; dwThread++ ) { std::thread& curThread = ahThread[dwThread]; curThread.join(); } CodecError err = CE_OK; for(CMP_DWORD dwThread = 0; dwThread < dwThreadCount; dwThread++) { CATICompressThreadData& threadData = aThreadData[dwThread]; if(err == CE_OK) err = threadData.m_errorCode; ahThread[dwThread] = std::thread(); } return GetError(err); } #endif // THREADED_COMPRESS