TexConv/CMP_Framework/Compute_Base.cpp

919 lines
33 KiB
C++
Raw Normal View History

2020-07-31 11:31:32 +08:00
//=====================================================================
// Copyright (c) 2020 Advanced Micro Devices, Inc. All rights reserved.
//
// 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 Compute_Base.cpp
//
//=====================================================================
#include <cstdlib>
#include "Compute_Base.h"
#include "PluginInterface.h"
#include "Texture.h"
#include "CMP_Core.h"
#ifndef _WIN32
#include <unistd.h> /* For open(), creat() */
#endif
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <string>
const CMP_CHAR* GetFormatDesc(CMP_FORMAT nFormat);
PluginManager g_pluginManager;
PluginInterface_Encoder *plugin_encoder_codec = NULL;
static CMP_BOOL HostPluginsRegistered = FALSE;
static CMP_FORMAT cmp_format_hold = CMP_FORMAT_Unknown;
PluginInterface_Pipeline *g_ComputeBase = NULL;
static CMP_Compute_type ComputeType = CMP_CPU;
static int exitreg = false;
static int startupreg = false;
extern void *make_Plugin_DDS();
extern void *make_Plugin_HPC();
// CMP_Core Compression Codecs
extern void *make_Plugin_BC1();
extern void *make_Plugin_BC2();
extern void *make_Plugin_BC3();
extern void *make_Plugin_BC4();
extern void *make_Plugin_BC5();
extern void *make_Plugin_BC6H();
extern void *make_Plugin_BC6H_SF();
extern void *make_Plugin_BC7();
#ifdef USE_GTC
extern void *make_Plugin_GTC();
#endif
void CMP_RegisterHostPlugins() {
if (HostPluginsRegistered == FALSE) {
// Hosts
g_pluginManager.registerStaticPlugin("IMAGE", "DDS", (void*)make_Plugin_DDS);
g_pluginManager.registerStaticPlugin("PIPELINE","HPC", (void*)make_Plugin_HPC);
// Encoders
g_pluginManager.registerStaticPlugin("ENCODER", "BC1", (void*)make_Plugin_BC1);
g_pluginManager.registerStaticPlugin("ENCODER", "BC2", (void*)make_Plugin_BC2);
g_pluginManager.registerStaticPlugin("ENCODER", "BC3", (void*)make_Plugin_BC3);
g_pluginManager.registerStaticPlugin("ENCODER", "BC4", (void*)make_Plugin_BC4);
g_pluginManager.registerStaticPlugin("ENCODER", "BC5", (void*)make_Plugin_BC5);
g_pluginManager.registerStaticPlugin("ENCODER", "BC6H", (void*)make_Plugin_BC6H);
g_pluginManager.registerStaticPlugin("ENCODER", "BC6H_SF",(void*)make_Plugin_BC6H_SF);
g_pluginManager.registerStaticPlugin("ENCODER", "BC7", (void*)make_Plugin_BC7);
#ifdef USE_GTC
g_pluginManager.registerStaticPlugin("ENCODER", "GTC", (void*)make_Plugin_GTC);
#endif
g_pluginManager.getPluginList(".",TRUE);
HostPluginsRegistered = TRUE;
}
}
//
// Closes the Compute library allocation
//
CMP_ERROR CMP_API CMP_DestroyComputeLibrary(bool forceclose = false) {
if (g_ComputeBase && forceclose) {
if (plugin_encoder_codec) {
delete plugin_encoder_codec;
plugin_encoder_codec = NULL;
}
g_ComputeBase->TC_Close();
//free(g_ComputeBase);
delete g_ComputeBase;
g_ComputeBase = NULL;
}
return CMP_OK;
}
const CMP_CHAR* GetEncodeWithDesc(CMP_Compute_type nFormat)
{
switch (nFormat)
{
case CMP_HPC: // Use CPU High Performance Compute to compress textures, full support
return "HPC";
break;
case CMP_GPU: // Use GPU to compress textures, full support
return "GPU";
break;
case CMP_GPU_OCL:
return "OCL";
break;
#ifdef USE_GPU_PIPELINE_VULKAN
case CMP_GPU_VLK:
return "VLK";
break;
#endif
case CMP_GPU_DXC:
return "DXC";
break;
}
return "CPU";
}
//-------------------------
// Application is "Exiting"
//-------------------------
void exiting() {
exitreg = false;
CMP_DestroyComputeLibrary(true);
}
//
// Initialize the Compute library based on support types
//
CMP_ERROR CMP_API CMP_CreateComputeLibrary(MipSet *srcTexture, KernelOptions *kernel_options, void *CMips) {
CMP_Compute_type CompType = kernel_options->encodeWith;
CMP_FORMAT cmp_format = kernel_options->format;
if ((CompType != ComputeType) || cmp_format != cmp_format_hold) {
CMP_DestroyComputeLibrary(true);
}
if (plugin_encoder_codec == NULL) {
plugin_encoder_codec = reinterpret_cast<PluginInterface_Encoder *>(g_pluginManager.GetPlugin("ENCODER", GetFormatDesc(cmp_format)));
if (plugin_encoder_codec == NULL) {
PrintInfo("Format [%s] for [%s] is not supported or failed to load\n", GetFormatDesc(cmp_format),GetEncodeWithDesc(CompType));
return CMP_ERR_UNABLE_TO_INIT_COMPUTELIB;
}
cmp_format_hold = cmp_format;
}
if (kernel_options->srcfile == NULL) {
kernel_options->srcfile = plugin_encoder_codec->TC_ComputeSourceFile(kernel_options->encodeWith);
if (kernel_options->srcfile == NULL) {
PrintInfo("Failed to load the encoders shader code\n");
return CMP_ERR_NOSHADER_CODE_DEFINED;
}
}
// Initialize the compression codec, pass kernel options
kernel_options->height = srcTexture->dwHeight;
kernel_options->width = srcTexture->dwWidth;
if (plugin_encoder_codec->TC_Init(kernel_options) != 0) {
PrintInfo("Failed to init encoder\n");
return CMP_ERR_UNABLE_TO_INIT_COMPUTELIB;
}
if (plugin_encoder_codec->TC_PluginSetSharedIO(CMips) != 0) {
PrintInfo("Warning unable to set print IO\n");
}
// Are we re-running the same codec type
if (g_ComputeBase && (ComputeType == CompType)) {
return CMP_OK;
}
switch (CompType) {
default:
case CMP_HPC:
g_ComputeBase = reinterpret_cast<PluginInterface_Pipeline *>(g_pluginManager.GetPlugin("PIPELINE", "HPC"));
break;
case CMP_GPU:
case CMP_GPU_OCL:
g_ComputeBase = reinterpret_cast<PluginInterface_Pipeline *>(g_pluginManager.GetPlugin("PIPELINE", "GPU_OCL"));
break;
case CMP_GPU_DXC:
g_ComputeBase = reinterpret_cast<PluginInterface_Pipeline *>(g_pluginManager.GetPlugin("PIPELINE", "GPU_DXC"));
break;
#ifdef USE_GPU_PIPELINE_VULKAN
case CMP_GPU_VLK:
g_ComputeBase = reinterpret_cast<PluginInterface_Pipeline *>(g_pluginManager.GetPlugin("PIPELINE", "GPU_VLK"));
break;
#endif
}
if (g_ComputeBase) {
// some code here if needed
if (g_ComputeBase->TC_Init(kernel_options) != 0)
return CMP_ERR_UNABLE_TO_INIT_COMPUTELIB;
ComputeType = CompType;
// Init IO
if (g_ComputeBase->TC_PluginSetSharedIO(CMips) != 0)
return CMP_ERR_UNABLE_TO_INIT_COMPUTELIB;
} else return CMP_ERR_UNABLE_TO_INIT_COMPUTELIB;
if (!exitreg) {
exitreg = true;
std::atexit(exiting);
}
if (!startupreg) {
startupreg = true;
// reserved for any one time startup code need
}
return CMP_OK;
}
CMP_ERROR CMP_API CMP_GetPerformanceStats(KernelPerformanceStats* pPerfStats)
{
CMP_ERROR result;
if (g_ComputeBase) {
result = g_ComputeBase->TC_GetPerformanceStats(pPerfStats);
if (result != CMP_OK) return (result);
} else return CMP_ABORTED;
return CMP_OK;
}
CMP_ERROR CMP_API CMP_GetDeviceInfo(KernelDeviceInfo* pDeviceInfo)
{
CMP_ERROR result;
if (g_ComputeBase) {
result = g_ComputeBase->TC_GetDeviceInfo(pDeviceInfo);
if (result != CMP_OK) return (result);
} else return CMP_ABORTED;
return CMP_OK;
}
CMP_ERROR CMP_API CMP_CompressTexture(KernelOptions *options,CMP_MipSet srcMipSet,CMP_MipSet dstMipSet,CMP_Feedback_Proc pFeedback) {
CMP_ERROR result;
if (g_ComputeBase) {
result = g_ComputeBase->TC_Compress(options,srcMipSet,dstMipSet,pFeedback);
if (result != CMP_OK) return (result);
} else return CMP_ABORTED;
return CMP_OK;
}
CMP_ERROR CMP_API CMP_SetComputeOptions(ComputeOptions *options) {
options->plugin_compute = plugin_encoder_codec;
if (g_ComputeBase) {
g_ComputeBase->TC_SetComputeOptions(options);
} else return CMP_ERR_UNABLE_TO_INIT_COMPUTELIB;
return CMP_OK;
}
//==================== Compressonator =================================
CodecType GetCodecType2(CMP_FORMAT format)
{
switch (format)
{
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_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_ARGB_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: 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_BC5: return CT_ATI2N_XY;
case CMP_FORMAT_BC6H: return CT_BC6H;
case CMP_FORMAT_BC6H_SF: return CT_BC6H_SF;
case CMP_FORMAT_BC7: return CT_BC7;
case CMP_FORMAT_ASTC: return CT_ASTC;
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;
case CMP_FORMAT_GTC: return CT_GTC;
#ifdef USE_BASIS
case CMP_FORMAT_BASIS: return CT_BASIS;
#endif
default: return CT_Unknown;
}
}
CMP_DWORD CalcBufferSizeCT(CodecType nCodecType, CMP_DWORD dwWidth, CMP_DWORD dwHeight, CMP_BYTE nBlockWidth, CMP_BYTE nBlockHeight)
{
#ifdef USE_DBGTRACE
DbgTrace(("IN: nCodecType %d, dwWidth %d, dwHeight %d", nCodecType, dwWidth, dwHeight));
#endif
CMP_DWORD dwChannels;
CMP_DWORD dwBitsPerChannel;
CMP_DWORD buffsize = 0;
switch (nCodecType)
{
// Block size is 4x4 and 64 bits per block
case CT_DXT1:
case CT_ATI1N:
case CT_ATC_RGB:
case CT_ETC_RGB:
case CT_ETC2_RGB:
case CT_ETC2_SRGB:
case CT_ETC2_RGBA1:
case CT_ETC2_SRGBA1:
dwChannels = 1;
dwBitsPerChannel = 4;
dwWidth = ((dwWidth + 3) / 4) * 4;
dwHeight = ((dwHeight + 3) / 4) * 4;
buffsize = (dwWidth * dwHeight * dwChannels * dwBitsPerChannel) / 8;
break;
// Block size is 4x4 and 128 bits per block
case CT_ETC2_RGBA:
case CT_ETC2_SRGBA:
// dwChannels = 2;
// dwBitsPerChannel = 4;
// dwWidth = ((dwWidth + 3) / 4) * 4;
// dwHeight = ((dwHeight + 3) / 4) * 4;
// buffsize = (dwWidth * dwHeight * dwChannels * dwBitsPerChannel) / 8;
dwWidth = ((dwWidth + 3) / 4) * 4;
dwHeight = ((dwHeight + 3) / 4) * 4;
buffsize = dwWidth * dwHeight;
if (buffsize < 16)
buffsize = 16;
break;
// Block size is 4x4 and 128 bits per block
case CT_DXT3:
case CT_DXT5:
case CT_DXT5_xGBR:
case CT_DXT5_RxBG:
case CT_DXT5_RBxG:
case CT_DXT5_xRBG:
case CT_DXT5_RGxB:
case CT_DXT5_xGxR:
case CT_ATI2N:
case CT_ATI2N_XY:
case CT_ATI2N_DXT5:
case CT_ATC_RGBA_Explicit:
case CT_ATC_RGBA_Interpolated:
dwChannels = 2;
dwBitsPerChannel = 4;
dwWidth = ((dwWidth + 3) / 4) * 4;
dwHeight = ((dwHeight + 3) / 4) * 4;
buffsize = (dwWidth * dwHeight * dwChannels * dwBitsPerChannel) / 8;
break;
// Block size is 4x4 and 128 bits per block
case CT_BC6H:
case CT_BC6H_SF:
dwWidth = ((dwWidth + 3) / 4) * 4;
dwHeight = ((dwHeight + 3) / 4) * 4;
buffsize = dwWidth * dwHeight;
if (buffsize < 16)
buffsize = 16;
break;
// Block size is 4x4 and 128 bits per block
case CT_BC7:
dwWidth = ((dwWidth + 3) / 4) * 4;
dwHeight = ((dwHeight + 3) / 4) * 4;
buffsize = dwWidth * dwHeight;
if (buffsize < 16)
buffsize = 16;
break;
// Block size ranges from 4x4 to 12x12 and 128 bits per block
case CT_ASTC:
dwWidth = ((dwWidth + nBlockWidth - 1) / nBlockWidth) * 4;
dwHeight = ((dwHeight + nBlockHeight - 1) / nBlockHeight) * 4;
buffsize = dwWidth * dwHeight;
break;
#ifdef _WIN32
// Block size is 4x4 and 128 bits per block. in future releases its will vary in Block Sizes and bits per block may change to 256
case CT_GTC:
dwWidth = ((dwWidth + 3) / 4) * 4;
dwHeight = ((dwHeight + 3) / 4) * 4;
buffsize = dwWidth * dwHeight;
if (buffsize < (4 * 4))
buffsize = 4 * 4;
break;
#ifdef USE_BASIS
// Block size is 4x4 and 128 bits per block, needs conformation!!
case CT_BASIS:
dwWidth = ((dwWidth + 3) / 4) * 4;
dwHeight = ((dwHeight + 3) / 4) * 4;
buffsize = dwWidth * dwHeight;
if (buffsize < (4 * 4))
buffsize = 4 * 4;
break;
#endif
#endif
default:
return 0;
}
#ifdef USE_DBGTRACE
DbgTrace(("OUT: %d", buffsize));
#endif
return buffsize;
}
CMP_DWORD CalcBufferSize2(CMP_FORMAT format, CMP_DWORD dwWidth, CMP_DWORD dwHeight, CMP_DWORD dwPitch, CMP_BYTE nBlockWidth, CMP_BYTE nBlockHeight)
{
#ifdef USE_DBGTRACE
DbgTrace(("format %d dwWidth %d dwHeight %d dwPitch %d", format, dwWidth, dwHeight, dwPitch));
#endif
switch (format)
{
case CMP_FORMAT_RGBA_8888:
case CMP_FORMAT_BGRA_8888:
case CMP_FORMAT_ARGB_8888:
case CMP_FORMAT_ARGB_2101010:
return ((dwPitch) ? (dwPitch * dwHeight) : (dwWidth * 4 * dwHeight));
case CMP_FORMAT_BGR_888:
case CMP_FORMAT_RGB_888:
return ((dwPitch) ? (dwPitch * dwHeight) : ((((dwWidth * 3) + 3) >> 2) * 4 * dwHeight));
case CMP_FORMAT_RG_8:
return ((dwPitch) ? (dwPitch * dwHeight) : (dwWidth * 2 * dwHeight));
case CMP_FORMAT_R_8:
return ((dwPitch) ? (dwPitch * dwHeight) : (dwWidth * dwHeight));
case CMP_FORMAT_ARGB_16:
case CMP_FORMAT_ARGB_16F:
return ((dwPitch) ? (dwPitch * dwHeight) : (dwWidth * 4 * sizeof(CMP_WORD) * dwHeight));
case CMP_FORMAT_RG_16:
case CMP_FORMAT_RG_16F:
return ((dwPitch) ? (dwPitch * dwHeight) : (dwWidth * 4 * sizeof(CMP_WORD) * dwHeight));
case CMP_FORMAT_R_16:
case CMP_FORMAT_R_16F:
return ((dwPitch) ? (dwPitch * dwHeight) : (dwWidth * 4 * sizeof(CMP_WORD) * dwHeight));
#ifdef ARGB_32_SUPPORT
case CMP_FORMAT_ARGB_32:
#endif // ARGB_32_SUPPORT
case CMP_FORMAT_ARGB_32F:
return ((dwPitch) ? (dwPitch * dwHeight) : (dwWidth * 4 * sizeof(float) * dwHeight));
#ifdef ARGB_32_SUPPORT
case CMP_FORMAT_RG_32:
#endif // ARGB_32_SUPPORT
case CMP_FORMAT_RG_32F:
return ((dwPitch) ? (dwPitch * dwHeight) : (dwWidth * 2 * sizeof(float) * dwHeight));
#ifdef ARGB_32_SUPPORT
case CMP_FORMAT_R_32:
#endif // ARGB_32_SUPPORT
case CMP_FORMAT_R_32F:
return ((dwPitch) ? (dwPitch * dwHeight) : (dwWidth * 1 * sizeof(float) * dwHeight));
default:
return CalcBufferSizeCT(GetCodecType2(format), dwWidth, dwHeight, nBlockWidth, nBlockHeight);
}
}
CMP_DWORD CMP_API CMP_CalculateBufferSize2(const CMP_Texture* pTexture)
{
#ifdef USE_DBGTRACE
DbgTrace(("-------> pTexture [%x]", pTexture));
#endif
assert(pTexture);
if (pTexture == NULL)
return 0;
assert(pTexture->dwSize == sizeof(CMP_Texture));
if (pTexture->dwSize != sizeof(CMP_Texture))
return 0;
assert(pTexture->dwWidth > 0);
if (pTexture->dwWidth <= 0)
return 0;
assert(pTexture->dwHeight > 0);
if (pTexture->dwHeight <= 0)
return 0;
assert(pTexture->format >= CMP_FORMAT_ARGB_8888 && pTexture->format <= CMP_FORMAT_MAX);
if (pTexture->format < CMP_FORMAT_ARGB_8888 || pTexture->format > CMP_FORMAT_MAX)
return 0;
return CalcBufferSize2(pTexture->format, pTexture->dwWidth, pTexture->dwHeight, pTexture->dwPitch, pTexture->nBlockWidth, pTexture->nBlockHeight);
}
//===========================================================================================================
CMP_ERROR CMP_API CMP_ProcessTexture(CMP_MipSet* srcMipSet, CMP_MipSet* dstMipSet, KernelOptions kernelOptions, CMP_Feedback_Proc pFeedbackProc) {
CMP_CMIPS CMips;
assert(srcMipSet);
assert(dstMipSet);
// -------------
// Output
// -------------
dstMipSet->m_Flags = MS_FLAG_Default;
dstMipSet->m_format = kernelOptions.format;
dstMipSet->m_nHeight = srcMipSet->m_nHeight;
dstMipSet->m_nWidth = srcMipSet->m_nWidth;
CMP_Format2FourCC(dstMipSet->m_format, dstMipSet);
//=====================================================
// Case Uncompressed Source to Compressed Destination
//=====================================================
// Allocate compression data
dstMipSet->m_ChannelFormat = CF_Compressed;
dstMipSet->m_nMaxMipLevels = srcMipSet->m_nMaxMipLevels;
dstMipSet->m_nMipLevels = 1; // this is overwriiten depending on input.
dstMipSet->m_nBlockWidth = 4; // Update is required for other sizes.
dstMipSet->m_nBlockHeight = 4; // - need to fix p_MipSetIn m_nBlock settings for this to work
dstMipSet->m_nBlockDepth = 1;
dstMipSet->m_nDepth = srcMipSet->m_nDepth;
dstMipSet->m_TextureType = srcMipSet->m_TextureType;
if (!CMips.AllocateMipSet(dstMipSet, dstMipSet->m_ChannelFormat, TDT_ARGB, dstMipSet->m_TextureType, srcMipSet->m_nWidth, srcMipSet->m_nHeight, dstMipSet->m_nDepth)) {
return CMP_ERR_MEM_ALLOC_FOR_MIPSET;
}
CMP_Texture srcTexture;
srcTexture.dwSize = sizeof(srcTexture);
int DestMipLevel = srcMipSet->m_nMipLevels;
dstMipSet->m_nMipLevels = DestMipLevel;
for (int nMipLevel = 0; nMipLevel < DestMipLevel; nMipLevel++) {
for (int nFaceOrSlice = 0; nFaceOrSlice < CMP_MaxFacesOrSlices(srcMipSet, nMipLevel); nFaceOrSlice++) {
//=====================
// Uncompressed source
//======================
MipLevel* pInMipLevel = CMips.GetMipLevel(srcMipSet, nMipLevel, nFaceOrSlice);
srcTexture.dwPitch = 0;
srcTexture.nBlockWidth = srcMipSet->m_nBlockWidth;
srcTexture.nBlockHeight = srcMipSet->m_nBlockHeight;
srcTexture.nBlockDepth = srcMipSet->m_nBlockDepth;
srcTexture.format = srcMipSet->m_format;
srcTexture.dwWidth = pInMipLevel->m_nWidth;
srcTexture.dwHeight = pInMipLevel->m_nHeight;
srcTexture.pData = pInMipLevel->m_pbData;
srcTexture.dwDataSize = CMP_CalculateBufferSize2(&srcTexture);
// Temporary setting!
srcMipSet->dwWidth = pInMipLevel->m_nWidth;
srcMipSet->dwHeight = pInMipLevel->m_nHeight;
srcMipSet->pData = pInMipLevel->m_pbData;
srcMipSet->dwDataSize = CMP_CalculateBufferSize2(&srcTexture);
//========================
// Compressed Destination
//========================
CMP_Texture destTexture;
destTexture.dwSize = sizeof(destTexture);
destTexture.dwWidth = pInMipLevel->m_nWidth;
destTexture.dwHeight = pInMipLevel->m_nHeight;
destTexture.dwPitch = 0;
destTexture.nBlockWidth = srcMipSet->m_nBlockWidth;
destTexture.nBlockHeight = srcMipSet->m_nBlockHeight;
destTexture.format = dstMipSet->m_format;
destTexture.dwDataSize = CMP_CalculateBufferSize2(&destTexture);
dstMipSet->m_format = dstMipSet->m_format;
dstMipSet->dwDataSize = CMP_CalculateBufferSize2(&destTexture);
dstMipSet->dwWidth = pInMipLevel->m_nWidth;
dstMipSet->dwHeight = pInMipLevel->m_nHeight;
MipLevel* pOutMipLevel = CMips.GetMipLevel(dstMipSet, nMipLevel, nFaceOrSlice);
if (!CMips.AllocateCompressedMipLevelData(pOutMipLevel, destTexture.dwWidth, destTexture.dwHeight, destTexture.dwDataSize)) {
return CMP_ERR_MEM_ALLOC_FOR_MIPSET;
}
destTexture.pData = pOutMipLevel->m_pbData;
dstMipSet->pData = pOutMipLevel->m_pbData;
//========================
// Process ConvertTexture
//========================
//------------------------------------------------
// Initializing the Host Framework
// if it fails revert to CPU version of the codec
//------------------------------------------------
ComputeOptions options;
options.force_rebuild = false; // set this to true if you want the shader source code to be allways compiled!
//===============================================================================
// Initalize the Pipeline that will be used for the codec to run on HPC or GPU
//===============================================================================
if (CMP_CreateComputeLibrary(srcMipSet, &kernelOptions, &CMips) != CMP_OK) {
PrintInfo("Failed to init HOST Lib. CPU will be used for compression\n");
return CMP_ERR_FAILED_HOST_SETUP;
}
// Init Compute Codec info IO
if ((CMips.PrintLine == NULL) && (PrintStatusLine != NULL)) {
CMips.PrintLine = PrintStatusLine;
}
// Set any addition feature as needed for the Host
if (CMP_SetComputeOptions(&options) != CMP_OK) {
CMP_DestroyComputeLibrary(false);
PrintInfo("Failed to setup SPMD GPU options\n");
return CMP_ERR_FAILED_HOST_SETUP;
}
// Do the compression
if (CMP_CompressTexture(&kernelOptions, *srcMipSet, *dstMipSet,pFeedbackProc) != CMP_OK) {
CMips.FreeMipSet(dstMipSet);
CMP_DestroyComputeLibrary(false);
PrintInfo("Failed to run compute plugin: CPU will be used for compression.\n");
return CMP_ERR_FAILED_HOST_SETUP;
}
// Get Performance Stats
if (kernelOptions.getPerfStats)
{
if (CMP_GetPerformanceStats(&kernelOptions.perfStats) != CMP_OK)
PrintInfo("Warning unable to get compute plugin performance stats\n");
}
//===============================================================================
// Close the Pipeline with option to cache as needed
//===============================================================================
CMP_DestroyComputeLibrary(false);
}
}
if (pFeedbackProc)
pFeedbackProc(100, NULL, NULL);
return CMP_OK;
}
//
// Block Level Encoder Support
//
CMP_ERROR CMP_API CMP_CreateBlockEncoder(void **block_encoder, CMP_EncoderSetting encodeSettings) {
CMP_RegisterHostPlugins();
PluginInterface_Encoder *encoder_codec;
encoder_codec = reinterpret_cast<PluginInterface_Encoder *>(g_pluginManager.GetPlugin("ENCODER", GetFormatDesc((CMP_FORMAT)encodeSettings.format)));
if (encoder_codec == NULL) {
PrintInfo("Failed to load [%s] encoder\n", GetFormatDesc((CMP_FORMAT)encodeSettings.format));
return CMP_ERR_UNABLE_TO_LOAD_ENCODER;
}
CMP_Encoder*blockEncoder = (CMP_Encoder*)encoder_codec->TC_Create();
if (blockEncoder == NULL) {
PrintInfo("Failed to create block encoder [%s]\n", GetFormatDesc((CMP_FORMAT)encodeSettings.format));
return CMP_ERR_UNABLE_TO_CREATE_ENCODER;
}
KernelOptions kernelOptions;
kernelOptions.height = encodeSettings.height;
kernelOptions.width = encodeSettings.width;
kernelOptions.fquality = encodeSettings.quality;
encoder_codec->TC_Init(&kernelOptions);
blockEncoder->m_quality = encodeSettings.quality;
blockEncoder->m_srcHeight = encodeSettings.height;
blockEncoder->m_srcWidth = encodeSettings.width;
*block_encoder = blockEncoder;
delete encoder_codec;
return CMP_OK;
}
CMP_ERROR CMP_API CMP_CompressBlock( void **block_encoder,void *SourceTexture, unsigned int sourceStride, void *DestTexture, unsigned int DestStride) {
CMP_Encoder *encoder = (CMP_Encoder*) *block_encoder;
encoder->m_srcStride = sourceStride;
encoder->m_dstStride = DestStride;
CMP_ERROR res = (CMP_ERROR)encoder->CompressBlock(0,0,SourceTexture,DestTexture);
return (res);
}
CMP_ERROR CMP_API CMP_CompressBlockXY( void **block_encoder,unsigned int x, unsigned int y, void *in, unsigned int sourceStride, void *out, unsigned int DestStride) {
CMP_Encoder *encoder = (CMP_Encoder*)*block_encoder;
encoder->m_srcStride = sourceStride;
encoder->m_dstStride = DestStride;
CMP_ERROR res = (CMP_ERROR)encoder->CompressBlock(x,y,in,out);
return (res);
}
void CMP_API CMP_DestroyBlockEncoder( void **block_encoder) {
delete *block_encoder;
}
void CMP_API CMP_GetMipLevel(CMP_MipLevel **data, const CMP_MipSet* pMipSet, int nMipLevel, int nFaceOrSlice) {
CMP_CMIPS CMips;
*data = CMips.GetMipLevel(pMipSet, nMipLevel, nFaceOrSlice);
}
//==============================
// FILE IO static plugin libs
//==============================
CMP_ERROR stb_load(const char *SourceFile, MipSet *MipSetIn) {
int Width, Height, ComponentCount;
unsigned char *pTempData = stbi_load(SourceFile, &Width, &Height, &ComponentCount, STBI_rgb_alpha);
if (pTempData == NULL)
{
return CMP_ERR_UNSUPPORTED_SOURCE_FORMAT;
}
CMP_CMIPS CMips;
memset(MipSetIn, 0, sizeof(MipSet));
if(!CMips.AllocateMipSet(MipSetIn, CF_8bit, TDT_ARGB,TT_2D,Width, Height, 1)) {
return CMP_ERR_MEM_ALLOC_FOR_MIPSET;
}
if(!CMips.AllocateMipLevelData(CMips.GetMipLevel(MipSetIn, 0), Width, Height, CF_8bit, TDT_ARGB)) {
return CMP_ERR_MEM_ALLOC_FOR_MIPSET;
}
MipSetIn->m_nMipLevels = 1;
MipSetIn->m_format = CMP_FORMAT_RGBA_8888;
CMP_BYTE* pData = CMips.GetMipLevel(MipSetIn,0)->m_pbData;
// RGBA : 8888 = 4 bytes
CMP_DWORD dwPitch = (4 * MipSetIn->m_nWidth);
CMP_DWORD dwSize = dwPitch * MipSetIn->m_nHeight;
memcpy(pData,pTempData,dwSize);
// Assign miplevel 0 to MipSetin pData ref
// both miplevel pData and mipset pData will point to the same location
// Typically mipset pData is assign a pointer to the current miplevel data been processed at run time
MipSetIn->pData = pData;
MipSetIn->dwDataSize = dwSize;
stbi_image_free(pTempData);
return CMP_OK;
}
void CMP_API CMP_FreeMipSet(CMP_MipSet *MipSetIn) {
if (!MipSetIn) return;
if (MipSetIn->m_pMipLevelTable) {
CMP_CMIPS CMips;
CMips.FreeMipSet(MipSetIn);
MipSetIn->m_pMipLevelTable = NULL;
}
}
char toupperChar(char ch)
{
return static_cast<char>(::toupper(static_cast<unsigned char>(ch)));
}
CMP_ERROR CMP_API CMP_LoadTexture(const char *SourceFile, CMP_MipSet *MipSetIn) {
CMP_RegisterHostPlugins();
CMP_CMIPS CMips;
CMP_ERROR status = CMP_OK;
std::string fn = SourceFile;
std::string file_extension = fn.substr(fn.find_last_of(".") + 1);
std::transform(file_extension.begin(), file_extension.end(),file_extension.begin(), toupperChar);
PluginInterface_Image *plugin_Image;
do {
plugin_Image = reinterpret_cast<PluginInterface_Image *>(g_pluginManager.GetPlugin("IMAGE",(char *)file_extension.c_str()));
// do the load
if (plugin_Image == NULL) {
status = CMP_ERR_PLUGIN_FILE_NOT_FOUND;
break;
} else {
plugin_Image->TC_PluginSetSharedIO(&CMips);
if (plugin_Image->TC_PluginFileLoadTexture(SourceFile, MipSetIn) != 0) {
// Process Error
delete plugin_Image;
plugin_Image = NULL;
status = CMP_ERR_UNABLE_TO_LOAD_FILE;
break;
}
delete plugin_Image;
plugin_Image = NULL;
}
} while(0);
// load failed: try stb lib
if (status != CMP_OK) {
status = stb_load(SourceFile, MipSetIn);
}
else {
// Make sure MipSetIn->pData is at top mip level
if (MipSetIn->pData == NULL) {
CMP_MipLevel* pOutMipLevel = CMips.GetMipLevel(MipSetIn, 0, 0);
MipSetIn->pData = pOutMipLevel->m_pbData;
MipSetIn->dwDataSize = pOutMipLevel->m_dwLinearSize;
MipSetIn->dwHeight = pOutMipLevel->m_nHeight;
MipSetIn->dwWidth = pOutMipLevel->m_nWidth;
}
}
return status;
}
CMP_ERROR CMP_API CMP_SaveTexture(const char * DestFile, CMP_MipSet *MipSetIn) {
CMP_RegisterHostPlugins();
bool filesaved = false;
CMIPS m_CMIPS;
std::string fn = DestFile;
std::string file_extension = fn.substr(fn.find_last_of(".") + 1);
std::transform(file_extension.begin(), file_extension.end(),file_extension.begin(), toupperChar);
if ((((file_extension.compare("DDS") == 0)|| file_extension.compare("KTX") == 0)) != TRUE) {
return CMP_ERR_INVALID_DEST_TEXTURE;
}
PluginInterface_Image *plugin_Image;
plugin_Image = reinterpret_cast<PluginInterface_Image *>(g_pluginManager.GetPlugin("IMAGE",(char *)file_extension.c_str()));
if (plugin_Image) {
bool holdswizzle = MipSetIn->m_swizzle;
if (plugin_Image->TC_PluginFileSaveTexture(DestFile,(MipSet*) MipSetIn) == 0) {
filesaved = true;
}
MipSetIn->m_swizzle = holdswizzle;
delete plugin_Image;
plugin_Image = NULL;
}
if (!filesaved) {
return CMP_ERR_GENERIC;
}
return CMP_OK;
}
CMP_INT CMP_API CMP_NumberOfProcessors(void) {
#ifndef _WIN32
return sysconf(_SC_NPROCESSORS_ONLN);
#else
// Figure out how many cores there are on this machine
//SYSTEM_INFO sysinfo;
//GetSystemInfo(&sysinfo);
//return (sysinfo.dwNumberOfProcessors);
return GetMaximumProcessorCount(0);
#endif
}