<commit_before>/* Copyright (c) 2017-2022 <NAME>
 *
 * 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.
 */

#include "texture_compression.hpp"
#include "texture_files.hpp"
#include "format.hpp"
#include "muglm/muglm_impl.hpp"
#include <vector>
#include <string.h>

#ifdef HAVE_ISPC
#include <ispc_texcomp.h>
#endif

#ifdef HAVE_ASTC_ENCODER
#include "astcenc.h"
#endif

#include "rgtc_compressor.hpp"
#define RGTC_DEBUG

using namespace muglm;

namespace Granite
{
VkFormat string_to_format(const std::string &s)
{
	if (s == "bc6h")
		return VK_FORMAT_BC6H_UFLOAT_BLOCK;
	else if (s == "bc7_unorm")
		return VK_FORMAT_BC7_UNORM_BLOCK;
	else if (s == "bc7_srgb")
		return VK_FORMAT_BC7_SRGB_BLOCK;
	else if (s == "bc1_unorm")
		return VK_FORMAT_BC1_RGB_UNORM_BLOCK;
	else if (s == "bc1_srgb")
		return VK_FORMAT_BC1_RGB_SRGB_BLOCK;
	else if (s == "bc3_unorm")
		return VK_FORMAT_BC3_UNORM_BLOCK;
	else if (s == "bc3_srgb")
		return VK_FORMAT_BC3_SRGB_BLOCK;
	else if (s == "bc4_unorm")
		return VK_FORMAT_BC4_UNORM_BLOCK;
	else if (s == "bc5_unorm")
		return VK_FORMAT_BC5_UNORM_BLOCK;
	else if (s == "rgba8_unorm")
		return VK_FORMAT_R8G8B8A8_UNORM;
	else if (s == "rg8_unorm")
		return VK_FORMAT_R8G8_UNORM;
	else if (s == "r8_unorm")
		return VK_FORMAT_R8_UNORM;
	else if (s == "rgba16_float")
		return VK_FORMAT_R16G16B16A16_SFLOAT;
	else if (s == "rg16_float")
		return VK_FORMAT_R16G16_SFLOAT;
	else if (s == "r16_float")
		return VK_FORMAT_R16_SFLOAT;
	else if (s == "rgba8_srgb")
		return VK_FORMAT_R8G8B8A8_SRGB;
	else if (s == "astc_4x4_srgb")
		return VK_FORMAT_ASTC_4x4_SRGB_BLOCK;
	else if (s == "astc_4x4_unorm")
		return VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
	else if (s == "astc_4x4_float")
		return VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT;
	else if (s == "astc_5x5_srgb")
		return VK_FORMAT_ASTC_5x5_SRGB_BLOCK;
	else if (s == "astc_5x5_unorm")
		return VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
	else if (s == "astc_5x5_float")
		return VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT;
	else if (s == "astc_6x6_srgb")
		return VK_FORMAT_ASTC_6x6_SRGB_BLOCK;
	else if (s == "astc_6x6_unorm")
		return VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
	else if (s == "astc_6x6_float")
		return VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT;
	else if (s == "astc_8x8_srgb")
		return VK_FORMAT_ASTC_8x8_SRGB_BLOCK;
	else if (s == "astc_8x8_unorm")
		return VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
	else if (s == "astc_8x8_float")
		return VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT;
	else
	{
		LOGE("Unknown format: %s.\n", s.c_str());
		return VK_FORMAT_UNDEFINED;
	}
}

#ifdef HAVE_ISPC
static unsigned output_format_to_input_stride(VkFormat format)
{
	switch (format)
	{
	case VK_FORMAT_BC7_UNORM_BLOCK:
	case VK_FORMAT_BC7_SRGB_BLOCK:
	case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
	case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
	case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
	case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
	case VK_FORMAT_BC3_UNORM_BLOCK:
	case VK_FORMAT_BC3_SRGB_BLOCK:
	case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
	case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
	case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
	case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
	case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
	case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
	case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
	case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
		return 4;

	case VK_FORMAT_BC6H_UFLOAT_BLOCK:
	case VK_FORMAT_BC6H_SFLOAT_BLOCK:
		return 8;

	default:
		return 0;
	}
}
#endif

struct CompressorState : std::enable_shared_from_this<CompressorState>
{
	std::shared_ptr<Vulkan::MemoryMappedTexture> input;
	std::shared_ptr<Vulkan::MemoryMappedTexture> output;

#ifdef HAVE_ISPC
	bc6h_enc_settings bc6 = {};
	bc7_enc_settings bc7 = {};
	astc_enc_settings astc = {};
#endif

	bool use_astc_encoder = false;
	bool use_hdr = false;

	unsigned block_size_x = 1;
	unsigned block_size_y = 1;

	void setup(const CompressorArguments &args);
	void enqueue_compression(ThreadGroup &group, const CompressorArguments &args);
	void enqueue_compression_block_ispc(TaskGroupHandle &group, const CompressorArguments &args, unsigned layer, unsigned level);
	void enqueue_compression_block_astc(TaskGroupHandle &group, const CompressorArguments &args, unsigned layer, unsigned level, TextureMode mode);
	void enqueue_compression_block_rgtc(TaskGroupHandle &group, const CompressorArguments &args, unsigned layer, unsigned level);
	void enqueue_compression_copy_8bit(TaskGroupHandle &group, const CompressorArguments &, unsigned layer, unsigned level);
	void enqueue_compression_copy_16bit(TaskGroupHandle &group, const CompressorArguments &, unsigned layer, unsigned level);

	double total_error[4] = {};
	std::mutex lock;
	TaskSignal *signal = nullptr;
};

void CompressorState::setup(const CompressorArguments &args)
{
	output->set_swizzle(args.output_mapping);
	output->set_generate_mipmaps_on_load(args.deferred_mipgen);
#ifdef HAVE_ISPC
	bool alpha = args.mode == TextureMode::sRGBA || args.mode == TextureMode::RGBA;
#endif
	auto &layout = input->get_layout();

	const auto is_8bit = [&]() -> bool {
		return layout.get_format() == VK_FORMAT_R8G8B8A8_SRGB ||
		       layout.get_format() == VK_FORMAT_R8G8B8A8_UNORM;
	};

#ifdef HAVE_ISPC
	const auto is_8bit_rgba = [&]() -> bool {
		return layout.get_format() == VK_FORMAT_R8G8B8A8_SRGB ||
		       layout.get_format() == VK_FORMAT_R8G8B8A8_UNORM;
	};
#endif

	const auto is_unorm = [&]() -> bool {
		return layout.get_format() == VK_FORMAT_R8G8B8A8_UNORM;
	};

#ifdef HAVE_ASTC_ENCODER
	const auto is_16bit_float = [&]() -> bool {
		return layout.get_format() == VK_FORMAT_R16G16B16A16_SFLOAT;
	};
#endif

	const auto handle_astc_ldr_format = [&](unsigned x, unsigned y) -> bool {
		block_size_x = x;
		block_size_y = y;
		if (!is_8bit())
		{
			LOGE("Input format to ASTC LDR must be 8-bit.\n");
			return false;
		}

#if defined(HAVE_ASTC_ENCODER)
		use_astc_encoder = true;
#elif defined(HAVE_ISPC)
		bool astc_w_swizzle = args.mode == TextureMode::NormalLA || args.mode == TextureMode::MaskLA;
		if (alpha || astc_w_swizzle)
		{
			if (args.quality <= 3)
				GetProfile_astc_alpha_fast(&astc, x, y);
			else
				GetProfile_astc_alpha_slow(&astc, x, y);
		}<commit_msg>Fix build when ASTC is not enabled.<commit_after>/* Copyright (c) 2017-2022 <NAME>
 *
 * 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.
 */

#include "texture_compression.hpp"
#include "texture_files.hpp"
#include "format.hpp"
#include "muglm/muglm_impl.hpp"
#include <vector>
#include <string.h>

#ifdef HAVE_ISPC
#include <ispc_texcomp.h>
#endif

#ifdef HAVE_ASTC_ENCODER
#include "astcenc.h"
#endif

#include "rgtc_compressor.hpp"
#define RGTC_DEBUG

using namespace muglm;

namespace Granite
{
VkFormat string_to_format(const std::string &s)
{
	if (s == "bc6h")
		return VK_FORMAT_BC6H_UFLOAT_BLOCK;
	else if (s == "bc7_unorm")
		return VK_FORMAT_BC7_UNORM_BLOCK;
	else if (s == "bc7_srgb")
		return VK_FORMAT_BC7_SRGB_BLOCK;
	else if (s == "bc1_unorm")
		return VK_FORMAT_BC1_RGB_UNORM_BLOCK;
	else if (s == "bc1_srgb")
		return VK_FORMAT_BC1_RGB_SRGB_BLOCK;
	else if (s == "bc3_unorm")
		return VK_FORMAT_BC3_UNORM_BLOCK;
	else if (s == "bc3_srgb")
		return VK_FORMAT_BC3_SRGB_BLOCK;
	else if (s == "bc4_unorm")
		return VK_FORMAT_BC4_UNORM_BLOCK;
	else if (s == "bc5_unorm")
		return VK_FORMAT_BC5_UNORM_BLOCK;
	else if (s == "rgba8_unorm")
		return VK_FORMAT_R8G8B8A8_UNORM;
	else if (s == "rg8_unorm")
		return VK_FORMAT_R8G8_UNORM;
	else if (s == "r8_unorm")
		return VK_FORMAT_R8_UNORM;
	else if (s == "rgba16_float")
		return VK_FORMAT_R16G16B16A16_SFLOAT;
	else if (s == "rg16_float")
		return VK_FORMAT_R16G16_SFLOAT;
	else if (s == "r16_float")
		return VK_FORMAT_R16_SFLOAT;
	else if (s == "rgba8_srgb")
		return VK_FORMAT_R8G8B8A8_SRGB;
	else if (s == "astc_4x4_srgb")
		return VK_FORMAT_ASTC_4x4_SRGB_BLOCK;
	else if (s == "astc_4x4_unorm")
		return VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
	else if (s == "astc_4x4_float")
		return VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT;
	else if (s == "astc_5x5_srgb")
		return VK_FORMAT_ASTC_5x5_SRGB_BLOCK;
	else if (s == "astc_5x5_unorm")
		return VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
	else if (s == "astc_5x5_float")
		return VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT;
	else if (s == "astc_6x6_srgb")
		return VK_FORMAT_ASTC_6x6_SRGB_BLOCK;
	else if (s == "astc_6x6_unorm")
		return VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
	else if (s == "astc_6x6_float")
		return VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT;
	else if (s == "astc_8x8_srgb")
		return VK_FORMAT_ASTC_8x8_SRGB_BLOCK;
	else if (s == "astc_8x8_unorm")
		return VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
	else if (s == "astc_8x8_float")
		return VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT;
	else
	{
		LOGE("Unknown format: %s.\n", s.c_str());
		return VK_FORMAT_UNDEFINED;
	}
}

#ifdef HAVE_ISPC
static unsigned output_format_to_input_stride(VkFormat format)
{
	switch (format)
	{
	case VK_FORMAT_BC7_UNORM_BLOCK:
	case VK_FORMAT_BC7_SRGB_BLOCK:
	case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
	case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
	case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
	case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
	case VK_FORMAT_BC3_UNORM_BLOCK:
	case VK_FORMAT_BC3_SRGB_BLOCK:
	case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
	case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
	case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
	case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
	case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
	case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
	case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
	case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
		return 4;

	case VK_FORMAT_BC6H_UFLOAT_BLOCK:
	case VK_FORMAT_BC6H_SFLOAT_BLOCK:
		return 8;

	default:
		return 0;
	}
}
#endif

struct CompressorState : std::enable_shared_from_this<CompressorState>
{
	std::shared_ptr<Vulkan::MemoryMappedTexture> input;
	std::shared_ptr<Vulkan::MemoryMappedTexture> output;

#ifdef HAVE_ISPC
	bc6h_enc_settings bc6 = {};
	bc7_enc_settings bc7 = {};
	astc_enc_settings astc = {};
#endif

	bool use_astc_encoder = false;
	bool use_hdr = false;

	unsigned block_size_x = 1;
	unsigned block_size_y = 1;

	void setup(const CompressorArguments &args);
	void enqueue_compression(ThreadGroup &group, const CompressorArguments &args);
	void enqueue_compression_block_ispc(TaskGroupHandle &group, const CompressorArguments &args, unsigned layer, unsigned level);
	void enqueue_compression_block_astc(TaskGroupHandle &group, const CompressorArguments &args, unsigned layer, unsigned level, TextureMode mode);
	void enqueue_compression_block_rgtc(TaskGroupHandle &group, const CompressorArguments &args, unsigned layer, unsigned level);
	void enqueue_compression_copy_8bit(TaskGroupHandle &group, const CompressorArguments &, unsigned layer, unsigned level);
	void enqueue_compression_copy_16bit(TaskGroupHandle &group, const CompressorArguments &, unsigned layer, unsigned level);

	double total_error[4] = {};
	std::mutex lock;
	TaskSignal *signal = nullptr;
};

void CompressorState::setup(const CompressorArguments &args)
{
	output->set_swizzle(args.output_mapping);
	output->set_generate_mipmaps_on_load(args.deferred_mipgen);
#ifdef HAVE_ISPC
	bool alpha = args.mode == TextureMode::sRGBA || args.mode == TextureMode::RGBA;
#endif
	auto &layout = input->get_layout();

	const auto is_8bit = [&]() -> bool {
		return layout.get_format() == VK_FORMAT_R8G8B8A8_SRGB ||
		       layout.get_format() == VK_FORMAT_R8G8B8A8_UNORM;
	};

#ifdef HAVE_ISPC
	const auto is_8bit_rgba = [&]() -> bool {
		return layout.get_format() == VK_FORMAT_R8G8B8A8_SRGB ||
		       layout.get_format() == VK_FORMAT_R8G8B8A8_UNORM;
	};
#endif

	const auto is_unorm = [&]() -> bool {
		return layout.get_format() == VK_FORMAT_R8G8B8A8_UNORM;
	};

#if defined(HAVE_ASTC_ENCODER) || defined(HAVE_ISPC)
	const auto is_16bit_float = [&]() -> bool {
		return layout.get_format() == VK_FORMAT_R16G16B16A16_SFLOAT;
	};
#endif

	const auto handle_astc_ldr_format = [&](unsigned x, unsigned y) -> bool {
		block_size_x = x;
		block_size_y = y;
		if (!is_8bit())
		{
			LOGE("Input format to ASTC LDR must be 8-bit.\n");
			return false;
		}

#if defined(HAVE_ASTC_ENCODER)
		use_astc_encoder = true;
#elif defined(HAVE_ISPC)
		bool astc_w_swizzle = args.mode == TextureMode::NormalLA || args.mode == TextureMode::MaskLA;
		if (alpha || astc_w_swizzle)
		{
			if (args.quality <= 3)
				GetProfile_astc_alpha_fast(&astc, x, y);
			else
				GetProfile_astc_alpha_slow(&astc, x, y);
		}
{'fraction_non_alphanumeric': 0.0944233206590621, 'fraction_numerical': 0.02577101816645543, 'mean_word_length': 5.705854579792256, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7232072', 'n_tokens_mistral': 5892, 'n_tokens_neox': 5613, 'n_words': 1263}