2023-04-28 15:47:06 +03:00
# include <iostream>
# include <string>
# include <map>
# include <tuple>
# include <algorithm>
# include <vulkan/vulkan.hpp>
# include <math.h>
# include <thread>
# include <mutex>
# include <numeric>
# include <fstream>
# include <iomanip>
# include <vector>
# include "stb_image_resize.h"
# include "stb_image.h"
# include "dfd.h"
# include "ispc_texcomp/ispc_texcomp.h"
# include "HalfFloat.h"
const std : : vector < std : : string > formatOrder = {
" BC1 " ,
" BC1_SRGB " ,
" BC4 " ,
" BC5 " ,
" BC3 " ,
" BC3_SRGB " ,
" BC6H " ,
" BC7 " ,
" BC7_SRGB "
} ;
const std : : map < std : : string , std : : tuple < std : : string , int , vk : : Format > > formats = {
{ " BC1 " , { " (DXT1) 5:6:5 Color, 1 bit alpha. 8 bytes per block. " , 8 , vk : : Format : : eBc1RgbUnormBlock } } ,
{ " BC1_SRGB " , { " (DXT1) 5:6:5 Color, 1 bit alpha. 8 bytes per block. " , 8 , vk : : Format : : eBc1RgbSrgbBlock } } ,
{ " BC4 " , { " Greyscale, 8 bytes per block. " , 8 , vk : : Format : : eBc4UnormBlock } } ,
{ " BC5 " , { " 2x BC4 images. 16 bytes per block. " , 16 , vk : : Format : : eBc5UnormBlock } } ,
{ " BC3 " , { " (DXT5) BC1 Color, BC4 Alpha, 16 bytes per block. " , 16 , vk : : Format : : eBc3UnormBlock } } ,
{ " BC3_SRGB " , { " (DXT5) BC1 Color, BC4 Alpha, 16 bytes per block. " , 16 , vk : : Format : : eBc3SrgbBlock } } ,
{ " BC6H " , { " 16 bit RGB, no alpha. Signed. 16 bytes per block. " , 16 , vk : : Format : : eBc6HUfloatBlock } } ,
{ " BC7 " , { " 8 bit RGBA - Good general purpose. 16 bytes per block. " , 16 , vk : : Format : : eBc7UnormBlock } } ,
{ " BC7_SRGB " , { " 8 bit RGBA - Good general purpose. 16 bytes per block. " , 16 , vk : : Format : : eBc7SrgbBlock } }
} ;
2023-08-16 01:27:48 +03:00
const std : : string usage = " [cube|array] <input> [input2, input3...] <output> <format> [fast|normal|slow|veryslow] [explicitmips] " ;
2023-04-28 15:47:06 +03:00
int main ( int argc , char * * argv )
{
ISPCInit ( ) ;
if ( argc < 4 ) {
2023-08-16 01:27:48 +03:00
std : : cerr < < " Usage: " < < argv [ 0 ] < < " " < < usage < < std : : endl ;
std : : cerr < < " Formats: " < < std : : endl ;
2023-04-28 15:47:06 +03:00
for ( auto & formatName : formatOrder ) {
auto format = formats . at ( formatName ) ;
2023-08-16 01:27:48 +03:00
std : : cerr < < " " < < formatName < < " - " < < std : : get < 0 > ( format ) < < std : : endl ;
2023-04-28 15:47:06 +03:00
}
2023-08-16 01:27:48 +03:00
return - 1 ;
2023-04-28 15:47:06 +03:00
}
int numInputs = argc - 3 ;
unsigned int inputsStart = 1 ;
std : : vector < std : : string > inputs ;
std : : string output ;
std : : string option ( argv [ 1 ] ) ;
if ( option = = " cube " | | option = = " array " ) {
numInputs - = 1 ;
inputsStart + = 1 ;
} else {
option = " none " ;
}
2023-04-28 19:06:32 +03:00
std : : string speedString ( argv [ argc - 1 ] ) ;
2023-04-28 15:47:06 +03:00
std : : string formatString ;
2023-04-28 19:06:32 +03:00
int speed = 2 ;
2023-08-16 01:27:48 +03:00
bool explicitmips = false ;
int formatPosition = - 1 ;
if ( speedString = = " explicitmips " ) {
speedString = std : : string ( argv [ argc - 2 ] ) ;
numInputs - = 1 ;
2023-10-11 00:38:41 +03:00
formatPosition - = 1 ;
2023-08-16 01:27:48 +03:00
explicitmips = true ;
}
2023-04-28 19:06:32 +03:00
if ( speedString = = " fast " | | speedString = = " normal " | | speedString = = " slow " | | speedString = = " veryslow " ) {
2023-04-28 15:47:06 +03:00
numInputs - = 1 ;
2023-08-16 01:27:48 +03:00
formatPosition - = 1 ;
2023-04-28 15:47:06 +03:00
2023-04-28 19:06:32 +03:00
if ( speedString = = " slow " ) {
speed = 1 ;
} else if ( speedString = = " veryslow " ) {
speed = 0 ;
} else if ( speedString = = " fast " ) {
speed = 3 ;
} else {
speed = 2 ;
2023-04-28 15:47:06 +03:00
}
}
2023-08-16 01:27:48 +03:00
formatString = std : : string ( argv [ argc + formatPosition ] ) ;
2023-04-28 15:47:06 +03:00
if ( numInputs < 1 ) {
2023-08-16 01:27:48 +03:00
std : : cerr < < " Usage: " < < argv [ 0 ] < < usage < < " " < < std : : endl ;
return - 1 ;
2023-04-28 15:47:06 +03:00
}
2023-10-11 00:38:41 +03:00
if ( explicitmips ) {
if ( option = = " cube " & & numInputs % 6 ! = 0 ) {
std : : cerr < < " Cube maps must have a multiple of 6 inputs. " < < std : : endl ;
return - 1 ;
}
} else {
if ( option = = " cube " & & numInputs ! = 6 ) {
std : : cerr < < " Cube maps must have 6 inputs. " < < std : : endl ;
return - 1 ;
}
2023-04-28 15:47:06 +03:00
}
if ( option = = " array " & & numInputs < 2 ) {
2023-08-16 01:27:48 +03:00
std : : cerr < < " Array maps must have at least 2 inputs. " < < std : : endl ;
return - 1 ;
}
if ( option = = " array " & & explicitmips ) {
std : : cerr < < " Explicit mips are not supported for arrays. " < < std : : endl ;
return - 1 ;
2023-04-28 15:47:06 +03:00
}
if ( formats . find ( formatString ) = = formats . end ( ) ) {
2023-08-16 01:27:48 +03:00
std : : cerr < < " Invalid format: " < < formatString < < std : : endl ;
std : : cerr < < usage < < std : : endl ;
std : : cerr < < " Formats: " < < std : : endl ;
2023-04-28 15:47:06 +03:00
for ( auto & formatName : formatOrder ) {
auto format = formats . at ( formatName ) ;
std : : cout < < " " < < formatName < < " - " < < std : : get < 0 > ( format ) < < std : : endl ;
}
return 1 ;
}
/* Check if it ends in SRGB */
bool srgb = false ;
if ( formatString . length ( ) > 5 & & formatString . substr ( formatString . length ( ) - 5 , 5 ) = = " _SRGB " ) {
srgb = true ;
}
bool hdr = false ;
if ( formatString . substr ( 0 , 3 ) = = " BC6 " ) {
hdr = true ;
}
for ( int i = inputsStart ; i < ( int ) ( inputsStart + numInputs ) ; i + + ) {
inputs . push_back ( std : : string ( argv [ i ] ) ) ;
}
output = std : : string ( argv [ inputsStart + numInputs ] ) ;
/* Print inputs and output */
std : : cout < < " Inputs: " < < std : : endl ;
for ( auto & input : inputs ) {
std : : cout < < " " < < input < < std : : endl ;
}
std : : cout < < " Output: " < < output < < std : : endl ;
std : : cout < < " Format: " < < formatString < < std : : endl ;
2023-04-28 19:06:32 +03:00
std : : cout < < " Speed: " < < speed < < std : : endl ;
2023-04-28 15:47:06 +03:00
int isa ;
isa = ISPCIsa ( ) ;
std : : string isaName ;
switch ( isa ) {
case 0 :
isaName = " SSE2 " ;
break ;
case 1 :
isaName = " SSE4 " ;
break ;
case 2 :
isaName = " AVX2 " ;
break ;
default :
isaName = " Unknown " ;
} ;
std : : cout < < " ISPC ISA: " < < isaName < < std : : endl ;
unsigned char * ldrBufferA , * ldrBufferB , * ldrBufferMain , * ldrBufferOther ;
float * hdrBufferA , * hdrBufferB , * hdrBufferMain , * hdrBufferOther ;
int width , height , channels ;
int copyChannels = 4 ;
int forcedChannels = 4 ;
if ( formatString = = " BC4 " ) {
copyChannels = 1 ;
} else if ( formatString = = " BC5 " ) {
copyChannels = 2 ;
}
std : : vector < std : : vector < std : : vector < unsigned char > > > ldrLevels ;
std : : vector < std : : vector < std : : vector < float > > > hdrLevels ;
std : : vector < std : : vector < std : : vector < std : : vector < unsigned char > > > > ldrLevelBlocks ;
std : : vector < std : : vector < std : : vector < std : : vector < uint16_t > > > > hdrLevelBlocks ;
if ( hdr ) {
hdrLevels . resize ( numInputs ) ;
hdrLevelBlocks . resize ( numInputs ) ;
} else {
ldrLevels . resize ( numInputs ) ;
ldrLevelBlocks . resize ( numInputs ) ;
}
2023-10-11 00:38:41 +03:00
unsigned int levelCount ;
int numFaces = 1 ;
int topLevelWidth , topLevelHeight ;
if ( option = = " cube " ) {
numFaces = 6 ;
}
2023-04-28 15:47:06 +03:00
2023-08-16 01:27:48 +03:00
if ( explicitmips ) {
2023-10-11 00:38:41 +03:00
levelCount = numInputs / numFaces ;
2023-04-28 15:47:06 +03:00
2023-10-11 00:38:41 +03:00
for ( int face = 0 ; face < numFaces ; face + + ) {
int levelWidth = 0 , levelHeight = 0 ;
2023-04-28 15:47:06 +03:00
2023-10-11 00:38:41 +03:00
for ( unsigned int level = 0 ; level < levelCount ; level + + ) {
std : : cout < < " Loading/scaling face " < < face < < " , level " < < level < < " , " < < inputs [ face * levelCount + level ] < < std : : endl ;
2023-04-28 15:47:06 +03:00
2023-10-11 00:38:41 +03:00
if ( hdr ) {
hdrBufferA = stbi_loadf ( inputs [ face * levelCount + level ] . c_str ( ) , & width , & height , & channels , forcedChannels ) ;
} else {
ldrBufferA = stbi_load ( inputs [ face * levelCount + level ] . c_str ( ) , & width , & height , & channels , forcedChannels ) ;
2023-08-16 01:27:48 +03:00
}
2023-04-28 15:47:06 +03:00
2023-10-11 00:38:41 +03:00
if ( level = = 0 ) {
levelWidth = width ;
levelHeight = height ;
topLevelWidth = width ;
topLevelHeight = height ;
} else {
if ( width ! = levelWidth | | height ! = levelHeight ) {
std : : cout < < " Input " < < inputs [ face * levelCount + level ] < < " for face " < < face < < " , level " < < level < < " dimensions " < < width < < " x " < < height < < " do not match expected " < < levelWidth < < " x " < < levelHeight < < std : : endl ;
return - 1 ;
}
}
2023-08-16 01:27:48 +03:00
2023-10-11 00:38:41 +03:00
if ( hdr ) {
hdrLevels [ face ] . push_back ( std : : vector < float > ( hdrBufferA , hdrBufferA + width * height * forcedChannels ) ) ;
stbi_image_free ( hdrBufferA ) ;
} else {
ldrLevels [ face ] . push_back ( std : : vector < uint8_t > ( ldrBufferA , ldrBufferA + width * height * forcedChannels ) ) ;
stbi_image_free ( ldrBufferA ) ;
}
levelWidth = std : : max ( 1 , ( int ) floorf ( ( float ) levelWidth / 2 ) ) ;
levelHeight = std : : max ( 1 , ( int ) floorf ( ( float ) levelHeight / 2 ) ) ;
}
2023-04-28 15:47:06 +03:00
}
2023-10-11 00:38:41 +03:00
width = topLevelWidth ;
height = topLevelHeight ;
2023-08-16 01:27:48 +03:00
} else {
for ( int input = 0 ; input < numInputs ; input + + ) {
int level = 0 ;
2023-04-28 15:47:06 +03:00
2023-08-16 01:27:48 +03:00
std : : cout < < " Loading/scaling " < < input < < " : " < < inputs [ input ] < < std : : endl ;
2023-04-28 15:47:06 +03:00
if ( hdr ) {
2023-08-16 01:27:48 +03:00
hdrBufferA = stbi_loadf ( inputs [ input ] . c_str ( ) , & width , & height , & channels , forcedChannels ) ;
if ( hdrBufferA = = nullptr ) {
std : : cout < < " Failed to load image: " < < inputs [ input ] < < std : : endl ;
return 1 ;
}
hdrBufferB = new float [ width * height * forcedChannels ] ;
hdrBufferMain = hdrBufferA ;
hdrBufferOther = hdrBufferB ;
2023-04-28 15:47:06 +03:00
} else {
2023-08-16 01:27:48 +03:00
ldrBufferA = stbi_load ( inputs [ input ] . c_str ( ) , & width , & height , & channels , forcedChannels ) ;
if ( ldrBufferA = = nullptr ) {
std : : cout < < " Failed to load image: " < < inputs [ input ] < < std : : endl ;
return 1 ;
}
ldrBufferB = new unsigned char [ width * height * forcedChannels ] ;
ldrBufferMain = ldrBufferA ;
ldrBufferOther = ldrBufferB ;
2023-04-28 15:47:06 +03:00
}
2023-08-16 01:27:48 +03:00
int oldWidth = width ;
int oldHeight = height ;
levelCount = 1 ;
{
int levelWidth = width ;
int levelHeight = height ;
while ( levelWidth > 1 | | levelHeight > 1 ) {
levelWidth = std : : max ( 1 , ( int ) floorf ( ( float ) levelWidth / 2 ) ) ;
levelHeight = std : : max ( 1 , ( int ) floorf ( ( float ) levelHeight / 2 ) ) ;
levelCount + + ;
}
2023-04-28 15:47:06 +03:00
}
2023-08-16 01:27:48 +03:00
while ( 1 ) {
if ( hdr ) {
hdrLevels [ input ] . push_back ( std : : vector < float > ( hdrBufferMain , hdrBufferMain + oldWidth * oldHeight * forcedChannels ) ) ;
} else {
ldrLevels [ input ] . push_back ( std : : vector < uint8_t > ( ldrBufferMain , ldrBufferMain + oldWidth * oldHeight * forcedChannels ) ) ;
}
2023-04-28 15:47:06 +03:00
2023-08-16 01:27:48 +03:00
if ( oldWidth = = 1 & & oldHeight = = 1 ) {
break ;
}
2023-04-28 15:47:06 +03:00
2023-08-16 01:27:48 +03:00
int newWidth = std : : max ( 1 , ( int ) floorf ( ( float ) oldWidth / 2 ) ) ;
int newHeight = std : : max ( 1 , ( int ) floorf ( ( float ) oldHeight / 2 ) ) ;
2023-04-28 15:47:06 +03:00
2023-08-16 01:27:48 +03:00
stbir_colorspace colorspace = srgb ? STBIR_COLORSPACE_SRGB : STBIR_COLORSPACE_LINEAR ;
int alphaChannel = channels = = 4 ? 3 : STBIR_ALPHA_CHANNEL_NONE ;
if ( hdr ) {
int rv = stbir_resize_float_generic ( hdrBufferMain , oldWidth , oldHeight , 0 , hdrBufferOther , newWidth , newHeight , 0 , forcedChannels , alphaChannel , 0 , STBIR_EDGE_CLAMP , STBIR_FILTER_MITCHELL , colorspace , nullptr ) ;
if ( rv ! = 1 ) {
std : : cerr < < " Error resizing " < < std : : endl ;
}
std : : swap ( hdrBufferMain , hdrBufferOther ) ;
} else {
int rv = stbir_resize_uint8_generic ( ldrBufferMain , oldWidth , oldHeight , 0 , ldrBufferOther , newWidth , newHeight , 0 , forcedChannels , alphaChannel , 0 , STBIR_EDGE_CLAMP , STBIR_FILTER_MITCHELL , colorspace , nullptr ) ;
if ( rv ! = 1 ) {
std : : cerr < < " Error resizing " < < std : : endl ;
}
std : : swap ( ldrBufferMain , ldrBufferOther ) ;
2023-04-28 15:47:06 +03:00
}
2023-08-16 01:27:48 +03:00
oldWidth = newWidth ;
oldHeight = newHeight ;
level + + ;
}
2023-04-28 15:47:06 +03:00
2023-08-16 01:27:48 +03:00
if ( hdr ) {
free ( hdrBufferA ) ;
delete [ ] hdrBufferB ;
} else {
free ( ldrBufferA ) ;
delete [ ] ldrBufferB ;
}
2023-04-28 15:47:06 +03:00
}
}
bc6h_enc_settings bc6henc ;
bc7_enc_settings bc7enc ;
if ( formatString = = " BC6H " ) {
2023-04-28 19:06:32 +03:00
if ( speed = = 0 ) {
GetProfile_bc6h_veryslow ( & bc6henc ) ;
} else if ( speed = = 1 ) {
GetProfile_bc6h_slow ( & bc6henc ) ;
} else if ( speed = = 2 ) {
2023-04-28 15:47:06 +03:00
GetProfile_bc6h_basic ( & bc6henc ) ;
2023-04-28 19:06:32 +03:00
} else if ( speed = = 3 ) {
GetProfile_bc6h_fast ( & bc6henc ) ;
2023-04-28 15:47:06 +03:00
}
} else {
if ( channels = = 3 ) {
2023-04-28 19:06:32 +03:00
if ( speed = = 0 | | speed = = 1 ) {
2023-04-28 15:47:06 +03:00
GetProfile_slow ( & bc7enc ) ;
2023-04-28 19:06:32 +03:00
} else if ( speed = = 2 ) {
GetProfile_basic ( & bc7enc ) ;
} else if ( speed = = 3 ) {
GetProfile_fast ( & bc7enc ) ;
2023-04-28 15:47:06 +03:00
}
} else {
2023-04-28 19:06:32 +03:00
if ( speed = = 0 | | speed = = 1 ) {
2023-04-28 15:47:06 +03:00
GetProfile_alpha_slow ( & bc7enc ) ;
2023-04-28 19:06:32 +03:00
} else if ( speed = = 2 ) {
GetProfile_alpha_basic ( & bc7enc ) ;
} else if ( speed = = 3 ) {
GetProfile_alpha_fast ( & bc7enc ) ;
2023-04-28 15:47:06 +03:00
}
}
}
std : : vector < std : : vector < std : : vector < unsigned char > > > levelBlocksCompressed ( numInputs ) ;
std : : tuple < std : : string , int , vk : : Format > format = formats . find ( formatString ) - > second ;
size_t blockSize = std : : get < 1 > ( format ) ;
2023-10-11 00:38:41 +03:00
for ( int face = 0 ; face < numFaces ; face + + ) {
2023-04-28 15:47:06 +03:00
if ( numInputs > 1 ) {
if ( option = = " cube " ) {
2023-10-11 00:38:41 +03:00
std : : cout < < " Face " < < face < < std : : endl ;
2023-04-28 15:47:06 +03:00
} else {
2023-10-11 00:38:41 +03:00
std : : cout < < " Layer " < < face < < std : : endl ;
2023-04-28 15:47:06 +03:00
}
}
if ( hdr ) {
2023-10-11 00:38:41 +03:00
hdrLevelBlocks [ face ] . resize ( levelCount ) ;
2023-04-28 15:47:06 +03:00
} else {
2023-10-11 00:38:41 +03:00
ldrLevelBlocks [ face ] . resize ( levelCount ) ;
2023-04-28 15:47:06 +03:00
}
int level = 0 ;
int oldWidth = width ;
int oldHeight = height ;
while ( 1 ) {
unsigned int blocksWidth = ( oldWidth + 3 ) / 4 ;
unsigned int blocksHeight = ( oldHeight + 3 ) / 4 ;
if ( hdr ) {
2023-10-11 00:38:41 +03:00
hdrLevelBlocks [ face ] [ level ] . resize ( blocksWidth * blocksHeight ) ;
2023-04-28 15:47:06 +03:00
for ( unsigned int y = 0 ; y < blocksHeight ; y + + ) {
for ( unsigned int x = 0 ; x < blocksWidth ; x + + ) {
std : : vector < uint16_t > block ( 16 * copyChannels ) ;
for ( unsigned int pixelY = y * 4 ; pixelY < y * 4 + 4 ; pixelY + + ) {
for ( unsigned int pixelX = x * 4 ; pixelX < x * 4 + 4 ; pixelX + + ) {
unsigned int clampedY = std : : min ( pixelY , ( unsigned int ) oldHeight - 1 ) ;
unsigned int clampedX = std : : min ( pixelX , ( unsigned int ) oldWidth - 1 ) ;
for ( int channel = 0 ; channel < copyChannels ; channel + + ) {
2023-10-11 00:38:41 +03:00
float value = hdrLevels [ face ] [ level ] [ ( clampedY * oldWidth + clampedX ) * forcedChannels + channel ] ;
2023-04-28 15:47:06 +03:00
if ( value < 0.0f ) {
value = 0.0f ;
}
if ( value > 65504.0f ) {
value = 65504.0f ;
}
block [ ( ( pixelY % 4 ) * 4 + ( pixelX % 4 ) ) * copyChannels + channel ] = HalfFloat : : FromFloat ( value ) ;
}
}
}
2023-10-11 00:38:41 +03:00
hdrLevelBlocks [ face ] [ level ] [ blocksWidth * y + x ] = block ;
2023-04-28 15:47:06 +03:00
}
}
} else {
2023-10-11 00:38:41 +03:00
ldrLevelBlocks [ face ] [ level ] . resize ( blocksWidth * blocksHeight ) ;
2023-04-28 15:47:06 +03:00
for ( unsigned int y = 0 ; y < blocksHeight ; y + + ) {
for ( unsigned int x = 0 ; x < blocksWidth ; x + + ) {
std : : vector < uint8_t > block ( 16 * copyChannels ) ;
for ( unsigned int pixelY = y * 4 ; pixelY < y * 4 + 4 ; pixelY + + ) {
for ( unsigned int pixelX = x * 4 ; pixelX < x * 4 + 4 ; pixelX + + ) {
unsigned int clampedY = std : : min ( pixelY , ( unsigned int ) oldHeight - 1 ) ;
unsigned int clampedX = std : : min ( pixelX , ( unsigned int ) oldWidth - 1 ) ;
for ( int channel = 0 ; channel < copyChannels ; channel + + ) {
2023-10-11 00:38:41 +03:00
block [ ( ( pixelY % 4 ) * 4 + ( pixelX % 4 ) ) * copyChannels + channel ] = ldrLevels [ face ] [ level ] [ ( clampedY * oldWidth + clampedX ) * forcedChannels + channel ] ;
2023-04-28 15:47:06 +03:00
}
}
}
2023-10-11 00:38:41 +03:00
ldrLevelBlocks [ face ] [ level ] [ blocksWidth * y + x ] = block ;
2023-04-28 15:47:06 +03:00
}
}
}
if ( oldWidth = = 1 & & oldHeight = = 1 ) {
break ;
}
oldWidth = std : : max ( 1 , ( int ) floorf ( ( float ) oldWidth / 2 ) ) ;
oldHeight = std : : max ( 1 , ( int ) floorf ( ( float ) oldHeight / 2 ) ) ;
level + + ;
2023-10-11 00:38:41 +03:00
if ( level > = levelCount ) {
break ;
}
2023-04-28 15:47:06 +03:00
}
/* Compress */
2023-10-11 00:38:41 +03:00
levelBlocksCompressed [ face ] . resize ( levelCount ) ;
2023-04-28 15:47:06 +03:00
for ( unsigned int l = 0 ; l < levelCount ; l + + ) {
if ( hdr ) {
2023-10-11 00:38:41 +03:00
levelBlocksCompressed [ face ] [ l ] . resize ( hdrLevelBlocks [ face ] [ l ] . size ( ) * blockSize ) ;
2023-04-28 15:47:06 +03:00
} else {
2023-10-11 00:38:41 +03:00
levelBlocksCompressed [ face ] [ l ] . resize ( ldrLevelBlocks [ face ] [ l ] . size ( ) * blockSize ) ;
2023-04-28 15:47:06 +03:00
}
}
std : : mutex mutex ;
std : : vector < unsigned int > completedBlocks ( levelCount , 0 ) ;
unsigned int numThreads = std : : thread : : hardware_concurrency ( ) ;
std : : vector < std : : thread > threads ;
unsigned int maxLevel = 0 ;
for ( unsigned t = 0 ; t < numThreads ; t + + ) {
threads . push_back ( std : : thread ( [ & , t ] ( ) {
for ( unsigned int l = 0 ; l < levelCount ; l + + ) {
unsigned int blocksPerThread ;
if ( hdr ) {
2023-10-11 00:38:41 +03:00
blocksPerThread = hdrLevelBlocks [ face ] [ l ] . size ( ) / numThreads ;
2023-04-28 15:47:06 +03:00
} else {
2023-10-11 00:38:41 +03:00
blocksPerThread = ldrLevelBlocks [ face ] [ l ] . size ( ) / numThreads ;
2023-04-28 15:47:06 +03:00
}
unsigned int startBlock = t * blocksPerThread ;
unsigned int endBlock = startBlock + blocksPerThread ;
if ( hdr ) {
if ( t = = numThreads - 1 ) {
2023-10-11 00:38:41 +03:00
endBlock = hdrLevelBlocks [ face ] [ l ] . size ( ) ;
2023-04-28 15:47:06 +03:00
}
} else {
if ( t = = numThreads - 1 ) {
2023-10-11 00:38:41 +03:00
endBlock = ldrLevelBlocks [ face ] [ l ] . size ( ) ;
2023-04-28 15:47:06 +03:00
}
}
for ( unsigned int b = startBlock ; b < endBlock ; b + + ) {
if ( formatString = = " BC6H " ) {
rgba_surface surface ;
2023-10-11 00:38:41 +03:00
surface . ptr = ( uint8_t * ) hdrLevelBlocks [ face ] [ l ] [ b ] . data ( ) ;
2023-04-28 15:47:06 +03:00
surface . width = 4 ;
surface . height = 4 ;
surface . stride = copyChannels * 4 * 2 ;
2023-10-11 00:38:41 +03:00
CompressBlocksBC6H ( & surface , & levelBlocksCompressed [ face ] [ l ] [ b * blockSize ] , & bc6henc ) ;
2023-04-28 15:47:06 +03:00
} else {
rgba_surface surface ;
2023-10-11 00:38:41 +03:00
surface . ptr = ldrLevelBlocks [ face ] [ l ] [ b ] . data ( ) ;
2023-04-28 15:47:06 +03:00
surface . width = 4 ;
surface . height = 4 ;
surface . stride = copyChannels * 4 ;
if ( formatString = = " BC1 " | | formatString = = " BC1_SRGB " ) {
2023-10-11 00:38:41 +03:00
CompressBlocksBC1 ( & surface , & levelBlocksCompressed [ face ] [ l ] [ b * blockSize ] ) ;
2023-04-28 15:47:06 +03:00
} else if ( formatString = = " BC3 " | | formatString = = " BC3_SRGB " ) {
2023-10-11 00:38:41 +03:00
CompressBlocksBC3 ( & surface , & levelBlocksCompressed [ face ] [ l ] [ b * blockSize ] ) ;
2023-04-28 15:47:06 +03:00
} else if ( formatString = = " BC4 " ) {
2023-10-11 00:38:41 +03:00
CompressBlocksBC4 ( & surface , & levelBlocksCompressed [ face ] [ l ] [ b * blockSize ] ) ;
2023-04-28 15:47:06 +03:00
} else if ( formatString = = " BC5 " ) {
2023-10-11 00:38:41 +03:00
CompressBlocksBC5 ( & surface , & levelBlocksCompressed [ face ] [ l ] [ b * blockSize ] ) ;
2023-04-28 15:47:06 +03:00
} else if ( formatString = = " BC7 " | | formatString = = " BC7_SRGB " ) {
2023-10-11 00:38:41 +03:00
CompressBlocksBC7 ( & surface , & levelBlocksCompressed [ face ] [ l ] [ b * blockSize ] , & bc7enc ) ;
2023-04-28 15:47:06 +03:00
}
}
std : : lock_guard < std : : mutex > lock ( mutex ) ;
completedBlocks [ l ] + + ;
if ( completedBlocks [ l ] % 100 = = 0 ) {
maxLevel = std : : max ( l , maxLevel ) ;
if ( l = = maxLevel ) {
float progress ;
if ( hdr ) {
2023-10-11 00:38:41 +03:00
progress = ( float ) completedBlocks [ l ] / hdrLevelBlocks [ face ] [ l ] . size ( ) ;
2023-04-28 15:47:06 +03:00
} else {
2023-10-11 00:38:41 +03:00
progress = ( float ) completedBlocks [ l ] / ldrLevelBlocks [ face ] [ l ] . size ( ) ;
2023-04-28 15:47:06 +03:00
}
int barWidth = 70 ;
std : : cout < < std : : setw ( 2 ) < < l < < " [ " ;
2023-04-28 19:06:32 +03:00
int pos = ( int ) ( barWidth * progress ) ;
2023-04-28 15:47:06 +03:00
for ( int i = 0 ; i < barWidth ; + + i ) {
if ( i < pos ) std : : cout < < " = " ;
else if ( i = = pos ) std : : cout < < " > " ;
else std : : cout < < " " ;
}
std : : cout < < " ] " < < std : : setw ( 2 ) < < int ( progress * 100.0 ) < < " % \r " ;
std : : cout . flush ( ) ;
}
}
}
}
} ) ) ;
}
for ( unsigned t = 0 ; t < numThreads ; t + + ) {
threads [ t ] . join ( ) ;
}
if ( hdr ) {
2023-10-11 00:38:41 +03:00
hdrLevelBlocks [ face ] . clear ( ) ;
2023-04-28 15:47:06 +03:00
} else {
2023-10-11 00:38:41 +03:00
ldrLevelBlocks [ face ] . clear ( ) ;
2023-04-28 15:47:06 +03:00
}
int barWidth = 70 ;
std : : cout < < std : : setw ( 2 ) < < ( levelCount - 1 ) < < " [ " ;
int pos = barWidth ;
for ( int i = 0 ; i < barWidth ; + + i ) {
if ( i < pos ) std : : cout < < " = " ;
else if ( i = = pos ) std : : cout < < " > " ;
else std : : cout < < " " ;
}
std : : cout < < " ] " < < std : : setw ( 2 ) < < 100 < < " % \r " ;
std : : cout . flush ( ) ;
std : : cout < < std : : endl ;
}
/* Write KTX2 */
std : : ofstream fh ( output , std : : ios : : out | std : : ios : : binary ) ;
if ( ! fh . is_open ( ) ) {
std : : cout < < " Failed to open output file: " < < output < < std : : endl ;
return 1 ;
}
const uint8_t identifier [ ] = { 0xAB , 0x4B , 0x54 , 0x58 , 0x20 , 0x32 , 0x30 , 0xBB , 0x0D , 0x0A , 0x1A , 0x0A } ;
fh . write ( ( char * ) identifier , sizeof ( identifier ) ) ;
vk : : Format vkformat = std : : get < 2 > ( formats . at ( formatString ) ) ;
fh . write ( ( char * ) & vkformat , sizeof ( vkformat ) ) ;
uint32_t typeSize = 1 ; // Fix for uncompressed vkformats, size of an individual component
fh . write ( ( char * ) & typeSize , sizeof ( typeSize ) ) ;
uint32_t pixelWidth = width ;
uint32_t pixelHeight = height ;
uint32_t pixelDepth = 0 ;
uint32_t layerCount ;
uint32_t faceCount ;
if ( numInputs > 1 ) {
if ( option = = " cube " ) {
layerCount = 0 ;
faceCount = 6 ;
} else {
layerCount = numInputs ;
faceCount = 1 ;
}
} else {
layerCount = 0 ;
faceCount = 1 ;
}
uint32_t supercompressionScheme = 0 ;
fh . write ( ( char * ) & pixelWidth , sizeof ( pixelWidth ) ) ;
fh . write ( ( char * ) & pixelHeight , sizeof ( pixelHeight ) ) ;
fh . write ( ( char * ) & pixelDepth , sizeof ( pixelDepth ) ) ;
fh . write ( ( char * ) & layerCount , sizeof ( layerCount ) ) ;
fh . write ( ( char * ) & faceCount , sizeof ( faceCount ) ) ;
fh . write ( ( char * ) & levelCount , sizeof ( levelCount ) ) ;
fh . write ( ( char * ) & supercompressionScheme , sizeof ( supercompressionScheme ) ) ;
uint32_t * dfd = vk2dfd ( * ( VkFormat * ) & vkformat ) ;
uint32_t dfdByteOffset = 0 ;
uint32_t dfdByteLength = dfd [ 0 ] ;
uint32_t kvdByteOffset = 0 ;
uint32_t kvdByteLength = 0 ;
uint64_t sgdByteOffset = 0 ;
uint64_t sgdByteLength = 0 ;
auto dfdByteOffsetPosition = fh . tellp ( ) ;
fh . write ( ( char * ) & dfdByteOffset , sizeof ( dfdByteOffset ) ) ;
fh . write ( ( char * ) & dfdByteLength , sizeof ( dfdByteLength ) ) ;
fh . write ( ( char * ) & kvdByteOffset , sizeof ( kvdByteOffset ) ) ;
fh . write ( ( char * ) & kvdByteLength , sizeof ( kvdByteLength ) ) ;
fh . write ( ( char * ) & sgdByteOffset , sizeof ( sgdByteOffset ) ) ;
fh . write ( ( char * ) & sgdByteLength , sizeof ( sgdByteLength ) ) ;
auto levelOffsetBytePosition = fh . tellp ( ) ;
for ( unsigned int i = 0 ; i < levelCount ; i + + ) {
uint64_t byteOffset = 0 ;
uint64_t byteLength = 0 ;
uint64_t uncompressedByteLength = 0 ;
fh . write ( ( char * ) & byteOffset , sizeof ( byteOffset ) ) ;
fh . write ( ( char * ) & byteLength , sizeof ( byteLength ) ) ;
fh . write ( ( char * ) & uncompressedByteLength , sizeof ( uncompressedByteLength ) ) ;
}
dfdByteOffset = fh . tellp ( ) ;
fh . write ( ( char * ) dfd , dfdByteLength ) ;
free ( dfd ) ;
kvdByteOffset = fh . tellp ( ) ;
fh . seekp ( dfdByteOffsetPosition ) ;
fh . write ( ( char * ) & dfdByteOffset , sizeof ( dfdByteOffset ) ) ;
fh . seekp ( kvdByteOffset ) ;
size_t alignment = std : : lcm ( ( size_t ) 4 , ( size_t ) std : : get < 1 > ( formats . at ( formatString ) ) ) ;
for ( int level = levelCount - 1 ; level > = 0 ; level - - ) {
// Alignment
while ( fh . tellp ( ) % alignment ! = 0 ) {
uint8_t padding = 0 ;
fh . write ( ( char * ) & padding , sizeof ( padding ) ) ;
}
auto levelBytePosition = fh . tellp ( ) ;
fh . seekp ( levelOffsetBytePosition + ( std : : ofstream : : pos_type ) ( level * 24 ) ) ;
uint64_t byteOffset = levelBytePosition ;
fh . write ( ( char * ) & byteOffset , sizeof ( byteOffset ) ) ;
2023-10-11 00:38:41 +03:00
uint64_t byteLength = levelBlocksCompressed [ 0 ] [ level ] . size ( ) * faceCount ;
2023-04-28 15:47:06 +03:00
fh . write ( ( char * ) & byteLength , sizeof ( byteLength ) ) ;
fh . write ( ( char * ) & byteLength , sizeof ( byteLength ) ) ;
fh . seekp ( levelBytePosition ) ;
2023-10-11 00:38:41 +03:00
for ( int face = 0 ; face < faceCount ; face + + ) {
fh . write ( ( char * ) levelBlocksCompressed [ face ] [ level ] . data ( ) , levelBlocksCompressed [ face ] [ level ] . size ( ) ) ;
2023-04-28 15:47:06 +03:00
}
}
return 0 ;
}