649 lines
24 KiB
C++
649 lines
24 KiB
C++
//===============================================================================
|
|
// 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 <assert.h>
|
|
#include <algorithm>
|
|
|
|
#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; i<maxCmds; i++)
|
|
pCodec->SetParameter(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; i<maxCmds; i++)
|
|
threadData.m_pCodec->SetParameter(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
|
|
|