| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <ImageProcessing_Traits_Platform.h>
- #include "ColorBlockRGBA4x4c.h"
- #include "ColorBlockRGBA4x4s.h"
- #include "ColorBlockRGBA4x4f.h"
- #include "CryTextureSquisher.h"
- #include <AzCore/std/parallel/mutex.h>
- #if defined(__clang__)
- # pragma clang diagnostic push
- # pragma clang diagnostic ignored "-Wnull-dereference"
- # pragma clang diagnostic ignored "-Wsometimes-uninitialized"
- # pragma clang diagnostic ignored "-Wshift-negative-value"
- #endif
- #if AZ_TRAIT_IMAGEPROCESSING_SQUISH_DO_NOT_USE_FASTCALL
- #define __fastcall
- #define _fastcall
- #define __assume(x)
- #endif
- #include <squish-ccr/squish.h>
- #if defined(__clang__)
- # pragma clang diagnostic pop
- #endif
- // number of bytes per block per type
- #define BLOCKSIZE_BC1 8
- #define BLOCKSIZE_BC2 16
- #define BLOCKSIZE_BC3 16
- #define BLOCKSIZE_BC4 8
- #define BLOCKSIZE_BC5 16
- #define BLOCKSIZE_BC6 16
- #define BLOCKSIZE_BC7 16
- #define BLOCKSIZE_CTX1 8
- #define BLOCKSIZE_LIMIT 16
- #define PTROFFSET_R 0
- #define PTROFFSET_G 1
- #define PTROFFSET_B 2
- #define PTROFFSET_A 3
- namespace ImageProcessingAtom
- {
- AZStd::mutex s_squishLock;
- /* -------------------------------------------------------------------------------------------------------------
- * internal presets
- */
- static struct ParameterMatrix
- {
- int flagsBaseline;
- int flagsUniform;
- int flagsPerceptual;
- int flagsQuality[CryTextureSquisher::EQualityProfile::eQualityProfile_Num];
- size_t offset;
- bool alphaOnly;
- } P2P[] =
- {
- // eCompressorPreset_BC1U,
- {
- squish::kBtc1 + squish::kExcludeAlphaFromPalette,
- squish::kColourMetricUniform,
- squish::kColourMetricPerceptual,
- { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit },
- 0, false
- },
- // eCompressorPreset_BC2U,
- {
- squish::kBtc2,
- squish::kColourMetricUniform,
- squish::kColourMetricPerceptual,
- { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit },
- 0, false
- },
- // eCompressorPreset_BC3U,
- {
- squish::kBtc3,
- squish::kColourMetricUniform,
- squish::kColourMetricPerceptual,
- { squish::kColourRangeFit, squish::kColourClusterFit + squish::kAlphaIterativeFit, squish::kColourIterativeClusterFit + squish::kAlphaIterativeFit, squish::kColourIterativeClusterFit + squish::kAlphaIterativeFit },
- 0, false
- },
- // eCompressorPreset_BC4U,
- {
- squish::kBtc4,
- squish::kColourMetricUniform,
- squish::kColourMetricUniform,
- { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
- PTROFFSET_R, false
- },
- // eCompressorPreset_BC5U,
- {
- squish::kBtc5,
- squish::kColourMetricUniform,
- squish::kColourMetricPerceptual,
- { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
- PTROFFSET_R, false
- },
- // eCompressorPreset_BC6UH,
- {
- squish::kBtc6,
- squish::kColourMetricUniform,
- squish::kColourMetricPerceptual,
- { squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourRangeFit },
- 0, false
- },
- // eCompressorPreset_BC7U,
- {
- squish::kBtc7,
- squish::kColourMetricUniform,
- squish::kColourMetricPerceptual,
- { squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit },
- 0, false
- },
- // eCompressorPreset_BC4S,
- {
- squish::kBtc4 + squish::kSignedInternal,
- squish::kColourMetricUniform,
- squish::kColourMetricUniform,
- { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
- PTROFFSET_R, false
- },
- // eCompressorPreset_BC5S,
- {
- squish::kBtc5 + squish::kSignedInternal,
- squish::kColourMetricUniform,
- squish::kColourMetricPerceptual,
- { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
- PTROFFSET_R, false
- },
- // eCompressorPreset_BC1Un,
- {
- squish::kBtc1 + squish::kExcludeAlphaFromPalette,
- squish::kColourMetricUnit,
- squish::kColourMetricUnit,
- { squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit },
- 0, false
- },
- // eCompressorPreset_BC2Un,
- {
- squish::kBtc2,
- squish::kColourMetricUnit,
- squish::kColourMetricUnit,
- { squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit },
- 0, false
- },
- // eCompressorPreset_BC3Un,
- {
- squish::kBtc3,
- squish::kColourMetricUnit,
- squish::kColourMetricUnit,
- { squish::kNormalRangeFit, squish::kNormalRangeFit + squish::kAlphaIterativeFit, squish::kNormalRangeFit + squish::kAlphaIterativeFit, squish::kNormalRangeFit + squish::kAlphaIterativeFit },
- 0, false
- },
- // eCompressorPreset_BC4Un,
- {
- squish::kBtc4,
- squish::kColourMetricUniform,
- squish::kColourMetricUniform,
- { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
- PTROFFSET_B, false
- },
- // eCompressorPreset_BC5Un,
- {
- squish::kBtc5,
- squish::kColourMetricUnit,
- squish::kColourMetricUnit,
- { 0, 0, squish::kNormalIterativeFit, squish::kNormalIterativeFit },
- PTROFFSET_R, false
- },
- // eCompressorPreset_BC6UHn,
- {
- squish::kBtc6,
- squish::kColourMetricUnit,
- squish::kColourMetricUnit,
- { squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit },
- 0, false
- },
- // eCompressorPreset_BC7Un,
- {
- squish::kBtc7,
- squish::kColourMetricUnit,
- squish::kColourMetricUnit,
- { squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit },
- 0, false
- },
- // eCompressorPreset_BC4Sn,
- {
- squish::kBtc4 + squish::kSignedInternal,
- squish::kColourMetricUniform,
- squish::kColourMetricUniform,
- { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
- PTROFFSET_B, false
- },
- // eCompressorPreset_BC5Sn,
- {
- squish::kBtc5 + squish::kSignedInternal,
- squish::kColourMetricUnit,
- squish::kColourMetricUnit,
- { 0, 0, squish::kNormalIterativeFit, squish::kNormalIterativeFit },
- PTROFFSET_R, false
- },
- // eCompressorPreset_BC1Ua,
- {
- squish::kBtc1 + squish::kWeightColourByAlpha,
- squish::kColourMetricUniform,
- squish::kColourMetricPerceptual,
- { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit },
- 0, false
- },
- // eCompressorPreset_BC2Ut,
- {
- squish::kBtc2 + squish::kWeightColourByAlpha,
- squish::kColourMetricUniform,
- squish::kColourMetricPerceptual,
- { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit },
- 0, false
- },
- // eCompressorPreset_BC3Ut,
- {
- squish::kBtc3 + squish::kWeightColourByAlpha,
- squish::kColourMetricUniform,
- squish::kColourMetricPerceptual,
- { squish::kColourRangeFit, squish::kColourClusterFit + squish::kAlphaIterativeFit, squish::kColourIterativeClusterFit + squish::kAlphaIterativeFit, squish::kColourIterativeClusterFit + squish::kAlphaIterativeFit },
- 0, false
- },
- // eCompressorPreset_BC4Ua,
- {
- squish::kBtc4,
- squish::kColourMetricUniform,
- squish::kColourMetricUniform,
- { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
- PTROFFSET_A, true
- },
- // eCompressorPreset_BC7Ut
- {
- squish::kBtc7 + squish::kWeightColourByAlpha,
- squish::kColourMetricUniform,
- squish::kColourMetricPerceptual,
- { squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit },
- 0, false
- },
- // eCompressorPreset_BC4Sa,
- {
- squish::kBtc4 + squish::kSignedInternal,
- squish::kColourMetricUniform,
- squish::kColourMetricUniform,
- { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
- PTROFFSET_A, true
- },
- // eCompressorPreset_BC7Ug
- {
- squish::kBtc7,
- squish::kColourMetricUniform,
- squish::kColourMetricUniform,
- { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourClusterFit * 15, squish::kColourClusterFit * 15 },
- 0, false
- },
- // eCompressorPreset_CTX1U
- {
- squish::kCtx1,
- squish::kColourMetricUniform,
- squish::kColourMetricUniform,
- { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit },
- 0, false
- },
- // eCompressorPreset_CTX1Un
- {
- squish::kCtx1,
- squish::kColourMetricUnit,
- squish::kColourMetricUnit,
- { squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit },
- 0, false
- },
- };
- /* -------------------------------------------------------------------------------------------------------------
- * compression functions
- */
- void CryTextureSquisher::Compress(const CryTextureSquisher::CompressorParameters& compress)
- {
- const unsigned int w = compress.width;
- const unsigned int h = compress.height;
- const size_t offset = P2P[compress.preset].offset;
- int flags = P2P[compress.preset].flagsBaseline + P2P[compress.preset].flagsQuality[compress.quality] +
- (!compress.perceptual ? P2P[compress.preset].flagsUniform : P2P[compress.preset].flagsPerceptual);
- const bool bAlphaOnly = P2P[compress.preset].alphaOnly;
- squish::sqio::dtp datatype;
- switch (compress.srcType)
- {
- case eBufferType_sint8:
- flags += squish::kSignedExternal;
- case eBufferType_uint8:
- datatype = squish::sqio::dtp::DT_U8;
- break;
- case eBufferType_sint16:
- flags += squish::kSignedExternal;
- case eBufferType_uint16:
- datatype = squish::sqio::dtp::DT_U16;
- break;
- case eBufferType_sfloat:
- flags += squish::kSignedExternal;
- case eBufferType_ufloat:
- datatype = squish::sqio::dtp::DT_F23;
- break;
- default:
- __assume(0);
- break;
- }
- if (compress.perceptual && (flags & squish::kColourMetricPerceptual))
- {
- flags |= squish::kColourMetricCustom;
- }
- const struct squish::sqio sqio = squish::GetSquishIO(w, h, datatype, flags);
- if (compress.perceptual && (flags & squish::kColourMetricPerceptual))
- {
- s_squishLock.lock();
- }
- if (compress.perceptual && (flags & squish::kColourMetricPerceptual))
- {
- squish::SetWeights(sqio.flags, &compress.weights[0]);
- }
- AZ_Assert(!(h & 3), "%s: Unexpected compress parameter of height", __FUNCTION__);
- switch (compress.srcType)
- {
- // compress an unsigned 8bit texture --------------------------------------------------
- // compress a signed 8bit texture -----------------------------------------------------
- case eBufferType_uint8:
- case eBufferType_sint8:
- {
- for (unsigned int y = 0U; y < h; y += 4U)
- {
- ColorBlockRGBA4x4c srcBlock;
- uint8 dstBlock[BLOCKSIZE_LIMIT];
- uint8* const targetBlock = dstBlock;
- const uint8* const sourceRgba = (const uint8*)srcBlock.colors() + offset;
- for (unsigned int x = 0U; x < w; x += 4U)
- {
- if (!bAlphaOnly)
- {
- srcBlock.setRGBA8(compress.srcBuffer, w, h, compress.pitch, x, y);
- }
- else
- {
- srcBlock.setA8(compress.srcBuffer, w, h, compress.pitch, x, y);
- }
- sqio.encoder(sourceRgba, 0xFFFF, targetBlock, sqio.flags);
- if (compress.userOutputFunction)
- {
- compress.userOutputFunction(compress, targetBlock, sqio.blocksize, y >> 2, x >> 2);
- }
- }
- }
- }
- break;
- // compress an unsigned 16bit texture -------------------------------------------------
- // compress a signed 16bit texture ----------------------------------------------------
- case eBufferType_uint16:
- case eBufferType_sint16:
- {
- for (unsigned int y = 0U; y < h; y += 4U)
- {
- ColorBlockRGBA4x4s srcBlock;
- uint8 dstBlock[BLOCKSIZE_LIMIT];
- uint8* const targetBlock = dstBlock;
- const float* const sourceRgba = (const float*)srcBlock.colors() + offset;
- for (unsigned int x = 0U; x < w; x += 4U)
- {
- if (!bAlphaOnly)
- {
- srcBlock.setRGBA16(compress.srcBuffer, w, h, compress.pitch, x, y);
- }
- else
- {
- srcBlock.setA16(compress.srcBuffer, w, h, compress.pitch, x, y);
- }
- sqio.encoder(sourceRgba, 0xFFFF, targetBlock, sqio.flags);
- if (compress.userOutputFunction)
- {
- compress.userOutputFunction(compress, targetBlock, sqio.blocksize, y >> 2, x >> 2);
- }
- }
- }
- }
- break;
- // compress an unsigned floating point texture ----------------------------------------
- // compress a signed floating point texture -------------------------------------------
- case eBufferType_ufloat:
- case eBufferType_sfloat:
- {
- for (unsigned int y = 0U; y < h; y += 4U)
- {
- ColorBlockRGBA4x4f srcBlock;
- uint8 dstBlock[BLOCKSIZE_LIMIT];
- uint8* const targetBlock = dstBlock;
- const float* const sourceRgba = (const float*)srcBlock.colors() + offset;
- for (unsigned int x = 0U; x < w; x += 4U)
- {
- if (!bAlphaOnly)
- {
- srcBlock.setRGBAf(compress.srcBuffer, w, h, compress.pitch, x, y);
- }
- else
- {
- srcBlock.setAf(compress.srcBuffer, w, h, compress.pitch, x, y);
- }
- sqio.encoder(sourceRgba, 0xFFFF, targetBlock, sqio.flags);
- if (compress.userOutputFunction)
- {
- compress.userOutputFunction(compress, targetBlock, sqio.blocksize, y >> 2, x >> 2);
- }
- }
- }
- }
- break;
- default:
- AZ_Assert(false, "%s: Unexpected compress source type", __FUNCTION__);
- break;
- }
- if (compress.perceptual && (flags & squish::kColourMetricPerceptual))
- {
- s_squishLock.unlock();
- }
- }
- void CryTextureSquisher::Decompress(const DecompressorParameters& decompress)
- {
- const unsigned int w = decompress.width;
- const unsigned int h = decompress.height;
- const size_t offset = P2P[decompress.preset].offset;
- int flags = P2P[decompress.preset].flagsBaseline +
- P2P[decompress.preset].flagsUniform;
- const bool bAlphaOnly = P2P[decompress.preset].alphaOnly;
- squish::sqio::dtp datatype;
- switch (decompress.dstType)
- {
- case eBufferType_sint8:
- flags += squish::kSignedExternal;
- case eBufferType_uint8:
- datatype = squish::sqio::dtp::DT_U8;
- break;
- case eBufferType_sint16:
- flags += squish::kSignedExternal;
- case eBufferType_uint16:
- datatype = squish::sqio::dtp::DT_U16;
- break;
- case eBufferType_sfloat:
- flags += squish::kSignedExternal;
- case eBufferType_ufloat:
- datatype = squish::sqio::dtp::DT_F23;
- break;
- default:
- __assume(0);
- break;
- }
- const struct squish::sqio sqio = squish::GetSquishIO(w, h, datatype, flags);
- AZ_Assert(!(h & 3), "%s: Unexpected compress parameter of height", __FUNCTION__);
- switch (decompress.dstType)
- {
- // decompress an unsigned 8bit texture --------------------------------------------------
- // decompress a signed 8bit texture -----------------------------------------------------
- case eBufferType_uint8:
- case eBufferType_sint8:
- {
- for (unsigned int y = 0U; y < h; y += 4U)
- {
- uint8 srcBlock[BLOCKSIZE_LIMIT];
- ColorBlockRGBA4x4c dstBlock;
- uint8* const sourceBlock = srcBlock;
- uint8* const targetRgba = (uint8*)dstBlock.colors() + offset;
- for (unsigned int x = 0U; x < w; x += 4U)
- {
- if (decompress.userInputFunction)
- {
- decompress.userInputFunction(decompress, sourceBlock, sqio.blocksize, y >> 2, x >> 2);
- }
- if (!bAlphaOnly)
- {
- dstBlock.setRGBA8(decompress.dstBuffer, w, h, decompress.pitch, x, y);
- }
- sqio.decoder(targetRgba, sourceBlock, sqio.flags);
- if (!bAlphaOnly)
- {
- dstBlock.getRGBA8(decompress.dstBuffer, w, h, decompress.pitch, x, y);
- }
- else
- {
- dstBlock.getA8(decompress.dstBuffer, w, h, decompress.pitch, x, y);
- }
- }
- }
- }
- break;
- // decompress an unsigned 16bit texture -------------------------------------------------
- // decompress a signed 16bit texture ----------------------------------------------------
- case eBufferType_uint16:
- case eBufferType_sint16:
- {
- for (unsigned int y = 0U; y < h; y += 4U)
- {
- uint8 srcBlock[BLOCKSIZE_LIMIT];
- ColorBlockRGBA4x4s dstBlock;
- uint8* const sourceBlock = srcBlock;
- uint16* const targetRgba = (uint16*)dstBlock.colors() + offset;
- for (unsigned int x = 0U; x < w; x += 4U)
- {
- if (decompress.userInputFunction)
- {
- decompress.userInputFunction(decompress, sourceBlock, sqio.blocksize, y >> 2, x >> 2);
- }
- if (!bAlphaOnly)
- {
- dstBlock.setRGBA16(decompress.dstBuffer, w, h, decompress.pitch, x, y);
- }
- sqio.decoder(targetRgba, sourceBlock, sqio.flags);
- if (!bAlphaOnly)
- {
- dstBlock.setRGBA16(decompress.dstBuffer, w, h, decompress.pitch, x, y);
- }
- else
- {
- dstBlock.getA16(decompress.dstBuffer, w, h, decompress.pitch, x, y);
- }
- }
- }
- }
- break;
- // decompress an unsigned floating point texture ----------------------------------------
- // decompress a signed floating point texture -------------------------------------------
- case eBufferType_ufloat:
- case eBufferType_sfloat:
- {
- for (unsigned int y = 0U; y < h; y += 4U)
- {
- uint8 srcBlock[BLOCKSIZE_LIMIT];
- ColorBlockRGBA4x4f dstBlock;
- uint8* const sourceBlock = srcBlock;
- float* const targetRgba = (float*)dstBlock.colors() + offset;
- for (unsigned int x = 0U; x < w; x += 4U)
- {
- if (decompress.userInputFunction)
- {
- decompress.userInputFunction(decompress, sourceBlock, sqio.blocksize, y >> 2, x >> 2);
- }
- if (!bAlphaOnly)
- {
- dstBlock.setRGBAf(decompress.dstBuffer, w, h, decompress.pitch, x, y);
- }
- sqio.decoder(targetRgba, sourceBlock, sqio.flags);
- if (!bAlphaOnly)
- {
- dstBlock.getRGBAf(decompress.dstBuffer, w, h, decompress.pitch, x, y);
- }
- else
- {
- dstBlock.getAf(decompress.dstBuffer, w, h, decompress.pitch, x, y);
- }
- }
- }
- }
- break;
- default:
- AZ_Assert(false, "%s: Unexpected compress destination type", __FUNCTION__);
- break;
- }
- }
- } // namespace ImageProcessingAtom
|