Merge branch 'branch'

This commit is contained in:
Rich Geldreich
2021-03-30 14:53:22 -04:00
14 changed files with 719 additions and 147 deletions

View File

@@ -49,7 +49,8 @@ namespace basist
{
cBASISHeaderFlagETC1S = 1, // Always set for ETC1S files. Not set for UASTC files.
cBASISHeaderFlagYFlipped = 2, // Set if the texture had to be Y flipped before encoding
cBASISHeaderFlagHasAlphaSlices = 4 // True if any slices contain alpha (for ETC1S, if the odd slices contain alpha data)
cBASISHeaderFlagHasAlphaSlices = 4, // True if any slices contain alpha (for ETC1S, if the odd slices contain alpha data)
cBASISHeaderFlagUsesGlobalCodebook = 8 // For ETC1S files, this will be true if the file utilizes a codebook from another .basis file.
};
// The image type field attempts to describe how to interpret the image data in a Basis file.

View File

@@ -7515,6 +7515,7 @@ namespace basist
#endif // BASISD_SUPPORT_PVRTC2
basisu_lowlevel_etc1s_transcoder::basisu_lowlevel_etc1s_transcoder(const etc1_global_selector_codebook* pGlobal_sel_codebook) :
m_pGlobal_codebook(nullptr),
m_pGlobal_sel_codebook(pGlobal_sel_codebook),
m_selector_history_buf_size(0)
{
@@ -7524,6 +7525,11 @@ namespace basist
uint32_t num_endpoints, const uint8_t* pEndpoints_data, uint32_t endpoints_data_size,
uint32_t num_selectors, const uint8_t* pSelectors_data, uint32_t selectors_data_size)
{
if (m_pGlobal_codebook)
{
BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 11\n");
return false;
}
bitwise_decoder sym_codec;
huffman_decoding_table color5_delta_model0, color5_delta_model1, color5_delta_model2, inten_delta_model;
@@ -7566,7 +7572,7 @@ namespace basist
const bool endpoints_are_grayscale = sym_codec.get_bits(1) != 0;
m_endpoints.resize(num_endpoints);
m_local_endpoints.resize(num_endpoints);
color32 prev_color5(16, 16, 16, 0);
uint32_t prev_inten = 0;
@@ -7574,8 +7580,8 @@ namespace basist
for (uint32_t i = 0; i < num_endpoints; i++)
{
uint32_t inten_delta = sym_codec.decode_huffman(inten_delta_model);
m_endpoints[i].m_inten5 = static_cast<uint8_t>((inten_delta + prev_inten) & 7);
prev_inten = m_endpoints[i].m_inten5;
m_local_endpoints[i].m_inten5 = static_cast<uint8_t>((inten_delta + prev_inten) & 7);
prev_inten = m_local_endpoints[i].m_inten5;
for (uint32_t c = 0; c < (endpoints_are_grayscale ? 1U : 3U); c++)
{
@@ -7589,21 +7595,21 @@ namespace basist
int v = (prev_color5[c] + delta) & 31;
m_endpoints[i].m_color5[c] = static_cast<uint8_t>(v);
m_local_endpoints[i].m_color5[c] = static_cast<uint8_t>(v);
prev_color5[c] = static_cast<uint8_t>(v);
}
if (endpoints_are_grayscale)
{
m_endpoints[i].m_color5[1] = m_endpoints[i].m_color5[0];
m_endpoints[i].m_color5[2] = m_endpoints[i].m_color5[0];
m_local_endpoints[i].m_color5[1] = m_local_endpoints[i].m_color5[0];
m_local_endpoints[i].m_color5[2] = m_local_endpoints[i].m_color5[0];
}
}
sym_codec.stop();
m_selectors.resize(num_selectors);
m_local_selectors.resize(num_selectors);
if (!sym_codec.init(pSelectors_data, selectors_data_size))
{
@@ -7657,9 +7663,9 @@ namespace basist
// TODO: Optimize this
for (uint32_t y = 0; y < 4; y++)
for (uint32_t x = 0; x < 4; x++)
m_selectors[i].set_selector(x, y, e[x + y * 4]);
m_local_selectors[i].set_selector(x, y, e[x + y * 4]);
m_selectors[i].init_flags();
m_local_selectors[i].init_flags();
}
}
else
@@ -7729,7 +7735,7 @@ namespace basist
for (uint32_t y = 0; y < 4; y++)
for (uint32_t x = 0; x < 4; x++)
m_selectors[q].set_selector(x, y, e[x + y * 4]);
m_local_selectors[q].set_selector(x, y, e[x + y * 4]);
}
else
{
@@ -7738,11 +7744,11 @@ namespace basist
uint32_t cur_byte = sym_codec.get_bits(8);
for (uint32_t k = 0; k < 4; k++)
m_selectors[q].set_selector(k, j, (cur_byte >> (k * 2)) & 3);
m_local_selectors[q].set_selector(k, j, (cur_byte >> (k * 2)) & 3);
}
}
m_selectors[q].init_flags();
m_local_selectors[q].init_flags();
}
}
else
@@ -7758,10 +7764,10 @@ namespace basist
uint32_t cur_byte = sym_codec.get_bits(8);
for (uint32_t k = 0; k < 4; k++)
m_selectors[i].set_selector(k, j, (cur_byte >> (k * 2)) & 3);
m_local_selectors[i].set_selector(k, j, (cur_byte >> (k * 2)) & 3);
}
m_selectors[i].init_flags();
m_local_selectors[i].init_flags();
}
}
else
@@ -7790,9 +7796,9 @@ namespace basist
prev_bytes[j] = static_cast<uint8_t>(cur_byte);
for (uint32_t k = 0; k < 4; k++)
m_selectors[i].set_selector(k, j, (cur_byte >> (k * 2)) & 3);
m_local_selectors[i].set_selector(k, j, (cur_byte >> (k * 2)) & 3);
}
m_selectors[i].init_flags();
m_local_selectors[i].init_flags();
continue;
}
@@ -7804,9 +7810,9 @@ namespace basist
prev_bytes[j] = static_cast<uint8_t>(cur_byte);
for (uint32_t k = 0; k < 4; k++)
m_selectors[i].set_selector(k, j, (cur_byte >> (k * 2)) & 3);
m_local_selectors[i].set_selector(k, j, (cur_byte >> (k * 2)) & 3);
}
m_selectors[i].init_flags();
m_local_selectors[i].init_flags();
}
}
}
@@ -7944,7 +7950,7 @@ namespace basist
approx_move_to_front selector_history_buf(m_selector_history_buf_size);
const uint32_t SELECTOR_HISTORY_BUF_FIRST_SYMBOL_INDEX = (uint32_t)m_selectors.size();
const uint32_t SELECTOR_HISTORY_BUF_FIRST_SYMBOL_INDEX = (uint32_t)m_local_selectors.size();
const uint32_t SELECTOR_HISTORY_BUF_RLE_SYMBOL_INDEX = m_selector_history_buf_size + SELECTOR_HISTORY_BUF_FIRST_SYMBOL_INDEX;
uint32_t cur_selector_rle_count = 0;
@@ -7977,6 +7983,13 @@ namespace basist
int prev_endpoint_pred_sym = 0;
int endpoint_pred_repeat_count = 0;
uint32_t prev_endpoint_index = 0;
const endpoint_vec& endpoints = m_pGlobal_codebook ? m_pGlobal_codebook->m_local_endpoints : m_local_endpoints;
const selector_vec& selectors = m_pGlobal_codebook ? m_pGlobal_codebook->m_local_selectors : m_local_selectors;
if (!endpoints.size() || !selectors.size())
{
BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: global codebooks must be unpacked first\n");
return false;
}
for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
{
@@ -8078,8 +8091,8 @@ namespace basist
const uint32_t delta_sym = sym_codec.decode_huffman(m_delta_endpoint_model);
endpoint_index = delta_sym + prev_endpoint_index;
if (endpoint_index >= m_endpoints.size())
endpoint_index -= (int)m_endpoints.size();
if (endpoint_index >= endpoints.size())
endpoint_index -= (int)endpoints.size();
}
pState->m_block_endpoint_preds[cur_block_endpoint_pred_array][block_x].m_endpoint_index = (uint16_t)endpoint_index;
@@ -8094,7 +8107,7 @@ namespace basist
{
cur_selector_rle_count--;
selector_sym = (int)m_selectors.size();
selector_sym = (int)selectors.size();
}
else
{
@@ -8118,17 +8131,17 @@ namespace basist
return false;
}
selector_sym = (int)m_selectors.size();
selector_sym = (int)selectors.size();
cur_selector_rle_count--;
}
}
if (selector_sym >= (int)m_selectors.size())
if (selector_sym >= (int)selectors.size())
{
assert(m_selector_history_buf_size > 0);
int history_buf_index = selector_sym - (int)m_selectors.size();
int history_buf_index = selector_sym - (int)selectors.size();
if (history_buf_index >= (int)selector_history_buf.size())
{
@@ -8153,7 +8166,7 @@ namespace basist
}
}
if ((endpoint_index >= m_endpoints.size()) || (selector_index >= m_selectors.size()))
if ((endpoint_index >= endpoints.size()) || (selector_index >= selectors.size()))
{
// The file is corrupted or we've got a bug.
BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: invalid datastream (5)\n");
@@ -8177,8 +8190,8 @@ namespace basist
}
#endif
const endpoint* pEndpoints = &m_endpoints[endpoint_index];
const selector* pSelector = &m_selectors[selector_index];
const endpoint* pEndpoints = &endpoints[endpoint_index];
const selector* pSelector = &selectors[selector_index];
switch (fmt)
{
@@ -8282,8 +8295,8 @@ namespace basist
const uint16_t* pAlpha_block = reinterpret_cast<uint16_t*>(static_cast<uint8_t*>(pAlpha_blocks) + (block_x + block_y * num_blocks_x) * sizeof(uint32_t));
const endpoint* pAlpha_endpoints = &m_endpoints[pAlpha_block[0]];
const selector* pAlpha_selector = &m_selectors[pAlpha_block[1]];
const endpoint* pAlpha_endpoints = &endpoints[pAlpha_block[0]];
const selector* pAlpha_selector = &selectors[pAlpha_block[1]];
const color32& alpha_base_color = pAlpha_endpoints->m_color5;
const uint32_t alpha_inten_table = pAlpha_endpoints->m_inten5;
@@ -8342,7 +8355,7 @@ namespace basist
{
#if BASISD_SUPPORT_ASTC
void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;
convert_etc1s_to_astc_4x4(pDst_block, pEndpoints, pSelector, transcode_alpha, &m_endpoints[0], &m_selectors[0]);
convert_etc1s_to_astc_4x4(pDst_block, pEndpoints, pSelector, transcode_alpha, &endpoints[0], &selectors[0]);
#else
assert(0);
#endif
@@ -8388,7 +8401,7 @@ namespace basist
void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;
convert_etc1s_to_pvrtc2_rgba(pDst_block, pEndpoints, pSelector, &m_endpoints[0], &m_selectors[0]);
convert_etc1s_to_pvrtc2_rgba(pDst_block, pEndpoints, pSelector, &endpoints[0], &selectors[0]);
#endif
break;
}
@@ -8680,7 +8693,7 @@ namespace basist
if (fmt == block_format::cPVRTC1_4_RGB)
fixup_pvrtc1_4_modulation_rgb((decoder_etc_block*)pPVRTC_work_mem, pPVRTC_endpoints, pDst_blocks, num_blocks_x, num_blocks_y);
else if (fmt == block_format::cPVRTC1_4_RGBA)
fixup_pvrtc1_4_modulation_rgba((decoder_etc_block*)pPVRTC_work_mem, pPVRTC_endpoints, pDst_blocks, num_blocks_x, num_blocks_y, pAlpha_blocks, &m_endpoints[0], &m_selectors[0]);
fixup_pvrtc1_4_modulation_rgba((decoder_etc_block*)pPVRTC_work_mem, pPVRTC_endpoints, pDst_blocks, num_blocks_x, num_blocks_y, pAlpha_blocks, &endpoints[0], &selectors[0]);
#endif // BASISD_SUPPORT_PVRTC1
if (pPVRTC_work_mem)
@@ -10378,46 +10391,84 @@ namespace basist
if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S)
{
if (m_lowlevel_etc1s_decoder.m_endpoints.size())
if (m_lowlevel_etc1s_decoder.m_local_endpoints.size())
{
m_lowlevel_etc1s_decoder.clear();
}
if (!pHeader->m_endpoint_cb_file_size || !pHeader->m_selector_cb_file_size || !pHeader->m_tables_file_size)
if (pHeader->m_flags & cBASISHeaderFlagUsesGlobalCodebook)
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted (0)\n");
if (!m_lowlevel_etc1s_decoder.get_global_codebooks())
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: File uses global codebooks, but set_global_codebooks() has not been called\n");
return false;
}
if (!m_lowlevel_etc1s_decoder.get_global_codebooks()->get_endpoints().size())
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: Global codebooks must be unpacked first by calling start_transcoding()\n");
return false;
}
if ((m_lowlevel_etc1s_decoder.get_global_codebooks()->get_endpoints().size() != pHeader->m_total_endpoints) ||
(m_lowlevel_etc1s_decoder.get_global_codebooks()->get_selectors().size() != pHeader->m_total_selectors))
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: Global codebook size mismatch (wrong codebooks for file).\n");
return false;
}
if (!pHeader->m_tables_file_size)
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted (2)\n");
return false;
}
if (pHeader->m_tables_file_ofs > data_size)
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (4)\n");
return false;
}
if (pHeader->m_tables_file_size > (data_size - pHeader->m_tables_file_ofs))
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (5)\n");
return false;
}
}
if ((pHeader->m_endpoint_cb_file_ofs > data_size) || (pHeader->m_selector_cb_file_ofs > data_size) || (pHeader->m_tables_file_ofs > data_size))
else
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (1)\n");
return false;
}
if (!pHeader->m_endpoint_cb_file_size || !pHeader->m_selector_cb_file_size || !pHeader->m_tables_file_size)
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted (0)\n");
return false;
}
if (pHeader->m_endpoint_cb_file_size > (data_size - pHeader->m_endpoint_cb_file_ofs))
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (2)\n");
return false;
}
if ((pHeader->m_endpoint_cb_file_ofs > data_size) || (pHeader->m_selector_cb_file_ofs > data_size) || (pHeader->m_tables_file_ofs > data_size))
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (1)\n");
return false;
}
if (pHeader->m_selector_cb_file_size > (data_size - pHeader->m_selector_cb_file_ofs))
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (3)\n");
return false;
}
if (pHeader->m_endpoint_cb_file_size > (data_size - pHeader->m_endpoint_cb_file_ofs))
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (2)\n");
return false;
}
if (pHeader->m_tables_file_size > (data_size - pHeader->m_tables_file_ofs))
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (3)\n");
return false;
}
if (pHeader->m_selector_cb_file_size > (data_size - pHeader->m_selector_cb_file_ofs))
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (3)\n");
return false;
}
if (!m_lowlevel_etc1s_decoder.decode_palettes(
pHeader->m_total_endpoints, pDataU8 + pHeader->m_endpoint_cb_file_ofs, pHeader->m_endpoint_cb_file_size,
pHeader->m_total_selectors, pDataU8 + pHeader->m_selector_cb_file_ofs, pHeader->m_selector_cb_file_size))
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: decode_palettes failed\n");
return false;
if (pHeader->m_tables_file_size > (data_size - pHeader->m_tables_file_ofs))
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (3)\n");
return false;
}
if (!m_lowlevel_etc1s_decoder.decode_palettes(
pHeader->m_total_endpoints, pDataU8 + pHeader->m_endpoint_cb_file_ofs, pHeader->m_endpoint_cb_file_size,
pHeader->m_total_selectors, pDataU8 + pHeader->m_selector_cb_file_ofs, pHeader->m_selector_cb_file_size))
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: decode_palettes failed\n");
return false;
}
}
if (!m_lowlevel_etc1s_decoder.decode_tables(pDataU8 + pHeader->m_tables_file_ofs, pHeader->m_tables_file_size))
@@ -10429,7 +10480,7 @@ namespace basist
else
{
// Nothing special to do for UASTC.
if (m_lowlevel_etc1s_decoder.m_endpoints.size())
if (m_lowlevel_etc1s_decoder.m_local_endpoints.size())
{
m_lowlevel_etc1s_decoder.clear();
}

View File

@@ -169,6 +169,8 @@ namespace basist
public:
basisu_lowlevel_etc1s_transcoder(const basist::etc1_global_selector_codebook *pGlobal_sel_codebook);
void set_global_codebooks(const basisu_lowlevel_etc1s_transcoder* pGlobal_codebook) { m_pGlobal_codebook = pGlobal_codebook; }
const basisu_lowlevel_etc1s_transcoder *get_global_codebooks() const { return m_pGlobal_codebook; }
bool decode_palettes(
uint32_t num_endpoints, const uint8_t *pEndpoints_data, uint32_t endpoints_data_size,
uint32_t num_selectors, const uint8_t *pSelectors_data, uint32_t selectors_data_size);
@@ -207,8 +209,8 @@ namespace basist
void clear()
{
m_endpoints.clear();
m_selectors.clear();
m_local_endpoints.clear();
m_local_selectors.clear();
m_endpoint_pred_model.clear();
m_delta_endpoint_model.clear();
m_selector_model.clear();
@@ -216,12 +218,20 @@ namespace basist
m_selector_history_buf_size = 0;
}
private:
// Low-level methods
typedef basisu::vector<endpoint> endpoint_vec;
endpoint_vec m_endpoints;
const endpoint_vec &get_endpoints() const { return m_local_endpoints; }
typedef basisu::vector<selector> selector_vec;
selector_vec m_selectors;
const selector_vec &get_selectors() const { return m_local_selectors; }
const etc1_global_selector_codebook* get_global_sel_codebook() const { return m_pGlobal_sel_codebook; }
private:
const basisu_lowlevel_etc1s_transcoder* m_pGlobal_codebook;
endpoint_vec m_local_endpoints;
selector_vec m_local_selectors;
const etc1_global_selector_codebook *m_pGlobal_sel_codebook;
@@ -487,6 +497,14 @@ namespace basist
void* pOutput_blocks, block_format fmt,
uint32_t block_stride_in_bytes, uint32_t output_row_pitch_in_blocks_or_pixels);
void set_global_codebooks(const basisu_lowlevel_etc1s_transcoder* pGlobal_codebook) { m_lowlevel_etc1s_decoder.set_global_codebooks(pGlobal_codebook); }
const basisu_lowlevel_etc1s_transcoder* get_global_codebooks() const { return m_lowlevel_etc1s_decoder.get_global_codebooks(); }
const basisu_lowlevel_etc1s_transcoder& get_lowlevel_etc1s_decoder() const { return m_lowlevel_etc1s_decoder; }
basisu_lowlevel_etc1s_transcoder& get_lowlevel_etc1s_decoder() { return m_lowlevel_etc1s_decoder; }
const basisu_lowlevel_uastc_transcoder& get_lowlevel_uastc_decoder() const { return m_lowlevel_uastc_decoder; }
basisu_lowlevel_uastc_transcoder& get_lowlevel_uastc_decoder() { return m_lowlevel_uastc_decoder; }
private:
mutable basisu_lowlevel_etc1s_transcoder m_lowlevel_etc1s_decoder;
mutable basisu_lowlevel_uastc_transcoder m_lowlevel_uastc_decoder;

View File

@@ -694,6 +694,11 @@ namespace basist
{
color32 m_color5;
uint8_t m_inten5;
bool operator== (const endpoint& rhs) const
{
return (m_color5.r == rhs.m_color5.r) && (m_color5.g == rhs.m_color5.g) && (m_color5.b == rhs.m_color5.b) && (m_inten5 == rhs.m_inten5);
}
bool operator!= (const endpoint& rhs) const { return !(*this == rhs); }
};
struct selector
@@ -706,6 +711,17 @@ namespace basist
uint8_t m_lo_selector, m_hi_selector;
uint8_t m_num_unique_selectors;
bool operator== (const selector& rhs) const
{
return (m_selectors[0] == rhs.m_selectors[0]) &&
(m_selectors[1] == rhs.m_selectors[1]) &&
(m_selectors[2] == rhs.m_selectors[2]) &&
(m_selectors[3] == rhs.m_selectors[3]);
}
bool operator!= (const selector& rhs) const
{
return !(*this == rhs);
}
void init_flags()
{