diff --git a/lib/src/AstcConverter.cpp b/lib/src/AstcConverter.cpp index 52ff96b..7e2d0ae 100644 --- a/lib/src/AstcConverter.cpp +++ b/lib/src/AstcConverter.cpp @@ -27,29 +27,114 @@ #include "astcenc.h" #include "astcenc_internal.h" -// Need to stub out these functions, since they don't work on all compilers. +// Need to stub out these functions, since they don't work on all compilers. Return true for all, +// since it will only be called if support was compiled in. int cpu_supports_sse41() { - return 0; + return 1; } int cpu_supports_popcnt() { - return 0; + return 1; } int cpu_supports_avx2() { - return 0; + return 1; } namespace cuttlefish { +static const unsigned int maxBlockSize = 12; + class AstcConverter::AstcThreadData : public Converter::ThreadData { public: + explicit AstcThreadData(AstcConverter& converter) + { + unsigned int flags = 0; + if (converter.m_alphaType == Texture::Alpha::Standard || + converter.m_alphaType == Texture::Alpha::PreMultiplied) + { + flags |= ASTCENC_FLG_USE_ALPHA_WEIGHT; + } + if (converter.m_colorSpace == ColorSpace::sRGB) + flags |= ASTCENC_FLG_USE_PERCEPTUAL; + + astcenc_preset preset; + switch (converter.m_quality) + { + case Texture::Quality::Lowest: + preset = ASTCENC_PRE_FASTEST; + break; + case Texture::Quality::Low: + preset = ASTCENC_PRE_FAST; + break; + case Texture::Quality::Normal: + preset = ASTCENC_PRE_MEDIUM; + break; + case Texture::Quality::High: + preset = ASTCENC_PRE_THOROUGH; + break; + case Texture::Quality::Highest: + preset = ASTCENC_PRE_EXHAUSTIVE; + break; + default: + assert(false); + return; + } + + astcenc_config config; + astcenc_config_init(converter.m_hdr ? ASTCENC_PRF_HDR : ASTCENC_PRF_LDR, converter.m_blockX, + converter.m_blockY, 1, preset, flags, config); + + astcenc_context_alloc(config, 1, &context); + + dummyImage.dim_x = converter.m_blockX; + dummyImage.dim_y = converter.m_blockY; + dummyImage.dim_z = 1; + dummyImage.data_type = ASTCENC_TYPE_F32; + dummyImage.data = nullptr; + + if (context->config.v_rgb_mean != 0.0f || context->config.v_rgb_stdev != 0.0f || + context->config.v_a_mean != 0.0f || context->config.v_a_stdev != 0.0f) + { + context->input_averages = m_inputAverages; + context->input_variances = m_inputVariances; + context->input_alpha_averages = m_inputAlphaAverages; + + astcenc_swizzle swizzle; + swizzle.r = converter.m_colorMask.r ? ASTCENC_SWZ_R : ASTCENC_SWZ_0; + swizzle.g = converter.m_colorMask.g ? ASTCENC_SWZ_G : ASTCENC_SWZ_0; + swizzle.b = converter.m_colorMask.b ? ASTCENC_SWZ_B : ASTCENC_SWZ_0; + if (converter.m_colorMask.a) + { + swizzle.a = converter.m_alphaType == Texture::Alpha::None ? + ASTCENC_SWZ_1 : ASTCENC_SWZ_A; + } + else + swizzle.a = ASTCENC_SWZ_0; + init_compute_averages_and_variances(dummyImage, context->config.v_rgb_power, + context->config.v_a_power, context->config.v_rgba_radius, + context->config.a_scale_radius, swizzle, context->arg, context->ag); + } + } + + ~AstcThreadData() + { + astcenc_context_free(context); + } + + astcenc_context* context; + astcenc_image dummyImage; compress_symbolic_block_buffers tempBuffers; + +private: + float4 m_inputAverages[maxBlockSize*maxBlockSize]; + float4 m_inputVariances[maxBlockSize*maxBlockSize]; + float m_inputAlphaAverages[maxBlockSize*maxBlockSize]; }; static bool initialize() @@ -62,72 +147,24 @@ static bool initialize() AstcConverter::AstcConverter(const Texture& texture, const Image& image, unsigned int blockX, unsigned int blockY, Texture::Quality quality) : Converter(image), m_blockX(blockX), m_blockY(blockY), - m_jobsX((image.width() + blockX - 1)/blockX), m_jobsY((image.height() + blockY - 1)/blockY) + m_jobsX((image.width() + blockX - 1)/blockX), m_jobsY((image.height() + blockY - 1)/blockY), + m_quality(quality), m_alphaType(texture.alphaType()), m_colorSpace(texture.colorSpace()), + m_colorMask(texture.colorMask()), m_hdr(texture.type() == Texture::Type::UFloat) { static bool initialized = initialize(); (void)initialized; - data().resize(m_jobsX*m_jobsY*blockSize); - assert(texture.type() == Texture::Type::UNorm || texture.type() == Texture::Type::UFloat); - m_colorMask = texture.colorMask(); - m_hdr = texture.type() == Texture::Type::UFloat; - - // Just need the image for sizing information. - m_dummyImage.reset(new astcenc_image); - m_dummyImage->dim_x = image.width(); - m_dummyImage->dim_y = image.height(); - m_dummyImage->dim_z = 1; - m_dummyImage->data_type = m_hdr ? ASTCENC_TYPE_F16 : ASTCENC_TYPE_U8; - m_dummyImage->data = nullptr; - - unsigned int flags = 0; - if (texture.alphaType() == Texture::Alpha::Standard || - texture.alphaType() == Texture::Alpha::PreMultiplied) - { - flags |= ASTCENC_FLG_USE_ALPHA_WEIGHT; - } - if (texture.colorSpace() == ColorSpace::sRGB) - flags |= ASTCENC_FLG_USE_PERCEPTUAL; - astcenc_config config; - astcenc_config_init(m_hdr ? ASTCENC_PRF_HDR : ASTCENC_PRF_LDR, m_blockX, m_blockY, 1, - static_cast(quality), flags, config); - - astcenc_context_alloc(config, 1, &m_context); - - if (m_context->config.v_rgb_mean != 0.0f || m_context->config.v_rgb_stdev != 0.0f || - m_context->config.v_a_mean != 0.0f || m_context->config.v_a_stdev != 0.0f) - { - unsigned int texelCount = image.width()*image.height(); - m_context->input_averages = new float4[texelCount]; - m_context->input_variances = new float4[texelCount]; - m_context->input_alpha_averages = new float[texelCount]; - - astcenc_swizzle swizzle; - swizzle.r = texture.colorMask().r ? ASTCENC_SWZ_R : ASTCENC_SWZ_0; - swizzle.g = texture.colorMask().g ? ASTCENC_SWZ_G : ASTCENC_SWZ_0; - swizzle.b = texture.colorMask().b ? ASTCENC_SWZ_B : ASTCENC_SWZ_0; - if (texture.colorMask().a) - swizzle.a = texture.alphaType() == Texture::Alpha::None ? ASTCENC_SWZ_1 : ASTCENC_SWZ_A; - else - swizzle.a = ASTCENC_SWZ_0; - init_compute_averages_and_variances(*m_dummyImage, m_context->config.v_rgb_power, - m_context->config.v_a_power, m_context->config.v_rgba_radius, - m_context->config.a_scale_radius, swizzle, m_context->arg, m_context->ag); - compute_averages_and_variances(*m_context, m_context->ag); - } + data().resize(m_jobsX*m_jobsY*blockSize); } AstcConverter::~AstcConverter() { - delete[] m_context->input_averages; - delete[] m_context->input_variances; - delete[] m_context->input_alpha_averages; - astcenc_context_free(m_context); } void AstcConverter::process(unsigned int x, unsigned int y, ThreadData* threadData) { + ColorRGBAf imageData[maxBlockSize*maxBlockSize]; imageblock astcBlock; astcBlock.xpos = x*m_blockX; astcBlock.ypos = y*m_blockY; @@ -139,6 +176,7 @@ void AstcConverter::process(unsigned int x, unsigned int y, ThreadData* threadDa for (unsigned int i = 0; i < m_blockX; ++i, ++index) { unsigned int scanlineIdx = std::min(x*m_blockX + i, image().width() - 1); + imageData[index] = scanline[scanlineIdx]; astcBlock.data_r[index] = scanline[scanlineIdx].r; astcBlock.data_g[index] = scanline[scanlineIdx].g; astcBlock.data_b[index] = scanline[scanlineIdx].b; @@ -149,20 +187,43 @@ void AstcConverter::process(unsigned int x, unsigned int y, ThreadData* threadDa } } + auto astcThreadData = static_cast(threadData); + void* imageDataPtr = imageData; + astcThreadData->dummyImage.data = &imageDataPtr; + // Fill in the rest of the information. imageblock_initialize_work_from_orig(&astcBlock, m_blockX*m_blockY); update_imageblock_flags(&astcBlock, m_blockX, m_blockY, 1); + astcenc_context* context = astcThreadData->context; + if (astcThreadData->context->input_averages) + { + // This assumes that it's going to be a pool of thread jobs, so always make sure there's + // exactly one job ready. + context->manage_avg_var.reset(); + context->manage_avg_var.init(1); + compute_averages_and_variances(*context, astcThreadData->context->ag); + } + symbolic_compressed_block symbolicBlock; auto block = reinterpret_cast( data().data() + (y*m_jobsX + x)*blockSize); - compress_block(*m_context, *m_dummyImage, &astcBlock, symbolicBlock, *block, - &reinterpret_cast(threadData)->tempBuffers); + compress_block(*context, astcThreadData->dummyImage, &astcBlock, symbolicBlock, *block, + &astcThreadData->tempBuffers); } std::unique_ptr AstcConverter::createThreadData() { - return std::unique_ptr(new AstcThreadData); +#if CUTTLEFISH_MSC +#pragma warning(push) +#pragma warning(disable: 4316) +#endif + + return std::unique_ptr(new AstcThreadData(*this)); + +#if CUTTLEFISH_MSC +#pragma warning(pop) +#endif } } // namespace cuttlefish diff --git a/lib/src/AstcConverter.h b/lib/src/AstcConverter.h index a8c9353..a95d860 100644 --- a/lib/src/AstcConverter.h +++ b/lib/src/AstcConverter.h @@ -44,16 +44,17 @@ class AstcConverter : public Converter private: class AstcThreadData; + friend class AstcThreadData; unsigned int m_blockX; unsigned int m_blockY; unsigned int m_jobsX; unsigned int m_jobsY; + Texture::Quality m_quality; + Texture::Alpha m_alphaType; + ColorSpace m_colorSpace; Texture::ColorMask m_colorMask; bool m_hdr; - - std::unique_ptr m_dummyImage; - astcenc_context* m_context; }; } // namespace cuttlefish diff --git a/lib/src/PvrtcConverter.cpp b/lib/src/PvrtcConverter.cpp index 6452a20..de85081 100644 --- a/lib/src/PvrtcConverter.cpp +++ b/lib/src/PvrtcConverter.cpp @@ -95,8 +95,30 @@ void PvrtcConverter::process(unsigned int, unsigned int, ThreadData*) return; } - pvrTexture.Transcode(pixelType, PVRTLVT_UnsignedByteNorm, PVRTLCS_Linear, - static_cast(m_quality)); + PVRTexLibCompressorQuality quality; + switch (m_quality) + { + case Texture::Quality::Lowest: + quality = PVRTLCQ_PVRTCFastest; + break; + case Texture::Quality::Low: + quality = PVRTLCQ_PVRTCLow; + break; + case Texture::Quality::Normal: + quality = PVRTLCQ_PVRTCNormal; + break; + case Texture::Quality::High: + quality = PVRTLCQ_PVRTCHigh; + break; + case Texture::Quality::Highest: + quality = PVRTLCQ_PVRTCBest; + break; + default: + assert(false); + return; + } + + pvrTexture.Transcode(pixelType, PVRTLVT_UnsignedByteNorm, PVRTLCS_Linear, quality); auto textureData = reinterpret_cast(pvrTexture.GetTextureDataPointer()); data().assign(textureData, textureData + pvrTexture.GetTextureDataSize()); diff --git a/lib/src/Texture.cpp b/lib/src/Texture.cpp index cba0e04..14518fd 100644 --- a/lib/src/Texture.cpp +++ b/lib/src/Texture.cpp @@ -1214,11 +1214,8 @@ bool Texture::convert(Format format, Type type, Quality quality, Alpha alphaType if (!imagesComplete() || !isFormatValid(format, type)) return false; - if (m_impl->colorSpace == ColorSpace::sRGB && (!hasNativeSRGB(format, type) || - type != Type::UNorm)) - { + if (m_impl->colorSpace == ColorSpace::sRGB && !hasNativeSRGB(format, type)) return false; - } m_impl->format = format; m_impl->type = type;