From d7390a182480d06724fc8429f14e4d0142e4607c Mon Sep 17 00:00:00 2001 From: Benau Date: Sun, 7 Aug 2022 15:33:54 +0800 Subject: [PATCH] Add GECompressorASTC4x4 --- .gitignore | 1 + cmake/Toolchain-ios-xcode.cmake | 2 + lib/graphics_engine/CMakeLists.txt | 44 ++++++ .../src/ge_compressor_astc_4x4.cpp | 134 ++++++++++++++++++ .../src/ge_compressor_astc_4x4.hpp | 29 ++++ .../src/ge_vulkan_command_loader.cpp | 8 +- .../src/ge_vulkan_command_loader.hpp | 2 + lib/graphics_engine/src/ge_vulkan_driver.cpp | 3 + .../src/ge_vulkan_features.cpp | 15 ++ .../src/ge_vulkan_features.hpp | 2 + lib/graphics_engine/src/ge_vulkan_texture.cpp | 11 +- 11 files changed, 249 insertions(+), 2 deletions(-) create mode 100644 lib/graphics_engine/src/ge_compressor_astc_4x4.cpp create mode 100644 lib/graphics_engine/src/ge_compressor_astc_4x4.hpp diff --git a/.gitignore b/.gitignore index 57326c5fb..08d4c471c 100644 --- a/.gitignore +++ b/.gitignore @@ -89,5 +89,6 @@ lib/openssl lib/harfbuzz lib/sdl2 lib/mbedtls +lib/astc-encoder .DS_Store diff --git a/cmake/Toolchain-ios-xcode.cmake b/cmake/Toolchain-ios-xcode.cmake index 20c83b798..62df662f4 100644 --- a/cmake/Toolchain-ios-xcode.cmake +++ b/cmake/Toolchain-ios-xcode.cmake @@ -59,6 +59,8 @@ set(LIBSAMPLERATE_LIBRARY ${PROJECT_SOURCE_DIR}/dependencies\${EFFECTIVE_PLATFOR set(LIBSAMPLERATE_INCLUDEDIR ${PROJECT_SOURCE_DIR}/dependencies-iphoneos/include CACHE STRING "") set(MOLTENVK_LIBRARY ${PROJECT_SOURCE_DIR}/dependencies\${EFFECTIVE_PLATFORM_NAME}/lib/libMoltenVK.a CACHE STRING "") set(VULKAN_INCLUDEDIR ${PROJECT_SOURCE_DIR}/dependencies-iphoneos/include CACHE STRING "") +set(LIBASTCENC_LIBRARY ${PROJECT_SOURCE_DIR}/dependencies\${EFFECTIVE_PLATFORM_NAME}/lib/libastcenc.a CACHE STRING "") +set(LIBASTCENC_INCLUDEDIR ${PROJECT_SOURCE_DIR}/dependencies-iphoneos/include CACHE STRING "") # For universal iOS and simulator set(LIBRESOLV_LIBRARY -lresolv CACHE STRING "") diff --git a/lib/graphics_engine/CMakeLists.txt b/lib/graphics_engine/CMakeLists.txt index 88f9b8329..67ec68e2e 100644 --- a/lib/graphics_engine/CMakeLists.txt +++ b/lib/graphics_engine/CMakeLists.txt @@ -1,3 +1,42 @@ +# Distro package just use libastcenc.so, find it first +find_library(LIBASTCENC_LIBRARY NAMES libastcenc astcenc astcenc-avx2-static astcenc-sse4.1-static astcenc-sse2-static astcenc-neon-static astcenc-native-static) +find_path(LIBASTCENC_INCLUDEDIR NAMES astcenc.h PATHS) +if (LIBASTCENC_LIBRARY AND LIBASTCENC_INCLUDEDIR) + set(ENABLE_LIBASTCENC 1) + add_definitions(-DENABLE_LIBASTCENC) + include_directories("${LIBASTCENC_INCLUDEDIR}") + message(STATUS "Use libastcenc: ${LIBASTCENC_LIBRARY}") + + if (NOT MSVC) + set(CMAKE_REQUIRED_FLAGS "-std=c++11") + endif() + set(CMAKE_REQUIRED_INCLUDES ${LIBASTCENC_INCLUDEDIR}) + set(CMAKE_REQUIRED_LIBRARIES ${LIBASTCENC_LIBRARY}) + include(CheckCXXSourceCompiles) + check_cxx_source_compiles(" + #define ASTCENC_DYNAMIC_LIBRARY 1 + #include + int main() + { + astcenc_context_free(NULL); + return 0; + } + " ASTCENC_DLL) + if (NOT MSVC) + unset(CMAKE_REQUIRED_FLAGS) + endif() + unset(CMAKE_REQUIRED_INCLUDES) + unset(CMAKE_REQUIRED_LIBRARIES) + if (ASTCENC_DLL) + message(STATUS "libastcenc: -DASTCENC_DYNAMIC_LIBRARY required") + add_definitions(-DASTCENC_DYNAMIC_LIBRARY) + endif() + +else() + message(WARNING "Missing astc-encoder for astc support, " + "visit https://github.com/ARM-software/astc-encoder for details") +endif() + include_directories("${PROJECT_SOURCE_DIR}/lib/graphics_engine/include") include_directories("${PROJECT_SOURCE_DIR}/lib/graphics_utils") include_directories("${PROJECT_SOURCE_DIR}/lib/irrlicht/include") @@ -24,6 +63,7 @@ endif() set(GE_SOURCES src/gl.c + src/ge_compressor_astc_4x4.cpp src/ge_compressor_s3tc_bc3.cpp src/ge_culling_tool.cpp src/ge_dx9_texture.cpp @@ -58,3 +98,7 @@ endif() add_library(graphics_engine STATIC ${GE_SOURCES}) target_link_libraries(graphics_engine ${SQUISH_LIBRARY}) + +if(ENABLE_LIBASTCENC) + target_link_libraries(graphics_engine ${LIBASTCENC_LIBRARY}) +endif() diff --git a/lib/graphics_engine/src/ge_compressor_astc_4x4.cpp b/lib/graphics_engine/src/ge_compressor_astc_4x4.cpp new file mode 100644 index 000000000..c634f9190 --- /dev/null +++ b/lib/graphics_engine/src/ge_compressor_astc_4x4.cpp @@ -0,0 +1,134 @@ +#include "ge_compressor_astc_4x4.hpp" + +#include "ge_main.hpp" +#include "ge_vulkan_command_loader.hpp" +#include "ge_vulkan_features.hpp" + +#include +#include +#include +#include + +#ifdef ENABLE_LIBASTCENC +#include +#include +#endif + +namespace GE +{ +// ============================================================================ +#ifdef ENABLE_LIBASTCENC +namespace GEVulkanFeatures +{ +extern bool g_supports_astc_4x4; +} + +std::vector g_astc_contexts; +#endif +// ============================================================================ +void GECompressorASTC4x4::init() +{ +#ifdef ENABLE_LIBASTCENC + if (!GEVulkanFeatures::g_supports_astc_4x4) + return; + + // Check for neon existence because libastcenc doesn't do that + // x86 will exit in astcenc_context_alloc if sse2 / sse4.1 is not supported +#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined (_M_ARM64) + if (SDL_HasNEON() == SDL_FALSE) + return; +#endif + + astcenc_config cfg = {}; + float quality = ASTCENC_PRE_FASTEST; + if (astcenc_config_init(ASTCENC_PRF_LDR, 4, 4, 1, quality, 0, &cfg) != + ASTCENC_SUCCESS) + return; + + for (unsigned i = 0; i < GEVulkanCommandLoader::getLoaderCount(); i++) + { + astcenc_context* context = NULL; + if (astcenc_context_alloc(&cfg, 1, &context) != ASTCENC_SUCCESS) + { + destroy(); + return; + } + g_astc_contexts.push_back(context); + } +#endif +} // init + +// ============================================================================ +void GECompressorASTC4x4::destroy() +{ +#ifdef ENABLE_LIBASTCENC + for (astcenc_context* context : g_astc_contexts) + astcenc_context_free(context); + g_astc_contexts.clear(); +#endif +} // destroy + +// ============================================================================ +bool GECompressorASTC4x4::loaded() +{ +#ifdef ENABLE_LIBASTCENC + return !g_astc_contexts.empty(); +#else + return false; +#endif +} // loaded + +// ---------------------------------------------------------------------------- +GECompressorASTC4x4::GECompressorASTC4x4(uint8_t* texture, unsigned channels, + const irr::core::dimension2d& size, + bool normal_map) + : GEMipmapGenerator(texture, channels, size, normal_map) +{ +#ifdef ENABLE_LIBASTCENC + assert(channels == 4); + size_t total_size = 0; + m_mipmap_sizes = 0; + for (unsigned i = 0; i < m_levels.size(); i++) + { + GEImageLevel& level = m_levels[i]; + unsigned cur_size = get4x4CompressedTextureSize(level.m_dim.Width, + level.m_dim.Height); + total_size += cur_size; + if (i > 0) + m_mipmap_sizes += cur_size; + } + + std::vector compressed_levels; + m_compressed_data = new uint8_t[total_size]; + uint8_t* cur_offset = m_compressed_data; + + for (GEImageLevel& level : m_levels) + { + astcenc_image img; + img.dim_x = level.m_dim.Width; + img.dim_y = level.m_dim.Height; + img.dim_z = 1; + img.data_type = ASTCENC_TYPE_U8; + img.data = &level.m_data; + + astcenc_swizzle swizzle; + swizzle.r = ASTCENC_SWZ_R; + swizzle.g = ASTCENC_SWZ_G; + swizzle.b = ASTCENC_SWZ_B; + swizzle.a = ASTCENC_SWZ_A; + + unsigned cur_size = get4x4CompressedTextureSize(level.m_dim.Width, + level.m_dim.Height); + if (astcenc_compress_image( + g_astc_contexts[GEVulkanCommandLoader::getLoaderId()], &img, + &swizzle, cur_offset, cur_size, 0) != ASTCENC_SUCCESS) + printf("astcenc_compress_image failed!\n"); + compressed_levels.push_back({ level.m_dim, cur_size, cur_offset }); + cur_offset += cur_size; + } + freeMipmapCascade(); + std::swap(compressed_levels, m_levels); +#endif +} // GECompressorASTC4x4 + +} diff --git a/lib/graphics_engine/src/ge_compressor_astc_4x4.hpp b/lib/graphics_engine/src/ge_compressor_astc_4x4.hpp new file mode 100644 index 000000000..9dc80094a --- /dev/null +++ b/lib/graphics_engine/src/ge_compressor_astc_4x4.hpp @@ -0,0 +1,29 @@ +#ifndef HEADER_GE_ASTC_COMPRESSOR_HPP +#define HEADER_GE_ASTC_COMPRESSOR_HPP + +#include "ge_mipmap_generator.hpp" + +namespace GE +{ +class GECompressorASTC4x4 : public GEMipmapGenerator +{ +private: + uint8_t* m_compressed_data; +public: + // ------------------------------------------------------------------------ + static void init(); + // ------------------------------------------------------------------------ + static void destroy(); + // ------------------------------------------------------------------------ + static bool loaded(); + // ------------------------------------------------------------------------ + GECompressorASTC4x4(uint8_t* texture, unsigned channels, + const irr::core::dimension2d& size, + bool normal_map); + // ------------------------------------------------------------------------ + ~GECompressorASTC4x4() { delete [] m_compressed_data; } +}; // GEASTCCompressor + +} + +#endif diff --git a/lib/graphics_engine/src/ge_vulkan_command_loader.cpp b/lib/graphics_engine/src/ge_vulkan_command_loader.cpp index eeaebe639..849c82d8b 100644 --- a/lib/graphics_engine/src/ge_vulkan_command_loader.cpp +++ b/lib/graphics_engine/src/ge_vulkan_command_loader.cpp @@ -84,7 +84,7 @@ void GEVulkanCommandLoader::init(GEVulkanDriver* vk) } } - g_loader_count.store(thread_count - 1); + g_loader_count.store(thread_count); for (unsigned i = 0; i < thread_count - 1; i++) { g_loaders.emplace_back( @@ -153,6 +153,12 @@ bool GEVulkanCommandLoader::isUsingMultiThreadingNow() return g_loader_id != 0; } // isUsingMultiThreadingNow +// ---------------------------------------------------------------------------- +unsigned GEVulkanCommandLoader::getLoaderCount() +{ + return g_loader_count.load(); +} // getLoaderCount + // ---------------------------------------------------------------------------- int GEVulkanCommandLoader::getLoaderId() { diff --git a/lib/graphics_engine/src/ge_vulkan_command_loader.hpp b/lib/graphics_engine/src/ge_vulkan_command_loader.hpp index 09c6d7066..6f647e798 100644 --- a/lib/graphics_engine/src/ge_vulkan_command_loader.hpp +++ b/lib/graphics_engine/src/ge_vulkan_command_loader.hpp @@ -19,6 +19,8 @@ bool multiThreadingEnabled(); // ---------------------------------------------------------------------------- bool isUsingMultiThreadingNow(); // ---------------------------------------------------------------------------- +unsigned getLoaderCount(); +// ---------------------------------------------------------------------------- int getLoaderId(); // ---------------------------------------------------------------------------- VkCommandPool getCurrentCommandPool(); diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index 53b761200..0711850fa 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -1,5 +1,6 @@ #include "ge_vulkan_driver.hpp" +#include "ge_compressor_astc_4x4.hpp" #include "ge_main.hpp" #include "ge_vulkan_2d_renderer.hpp" @@ -632,6 +633,7 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params, GEVulkanShaderManager::getSamplerSize(), GEVulkanShaderManager::getMeshTextureLayer(), GEVulkanFeatures::supportsBindMeshTexturesAtOnce()); + GECompressorASTC4x4::init(); GEVulkanFeatures::printStats(); } catch (std::exception& e) @@ -651,6 +653,7 @@ GEVulkanDriver::~GEVulkanDriver() // ---------------------------------------------------------------------------- void GEVulkanDriver::destroyVulkan() { + GECompressorASTC4x4::destroy(); if (m_depth_texture) { m_depth_texture->drop(); diff --git a/lib/graphics_engine/src/ge_vulkan_features.cpp b/lib/graphics_engine/src/ge_vulkan_features.cpp index 46b569e69..4644aca55 100644 --- a/lib/graphics_engine/src/ge_vulkan_features.cpp +++ b/lib/graphics_engine/src/ge_vulkan_features.cpp @@ -1,5 +1,6 @@ #include "ge_vulkan_features.hpp" +#include "ge_compressor_astc_4x4.hpp" #include "ge_vulkan_driver.hpp" #include "ge_vulkan_shader_manager.hpp" @@ -27,6 +28,7 @@ bool g_supports_multi_draw_indirect = false; bool g_supports_base_vertex_rendering = true; bool g_supports_compute_in_main_queue = false; bool g_supports_s3tc_bc3 = false; +bool g_supports_astc_4x4 = false; } // GEVulkanFeatures // ============================================================================ @@ -70,6 +72,10 @@ void GEVulkanFeatures::init(GEVulkanDriver* vk) vkGetPhysicalDeviceFormatProperties(vk->getPhysicalDevice(), VK_FORMAT_BC3_UNORM_BLOCK, &format_properties); g_supports_s3tc_bc3 = format_properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; + format_properties = {}; + vkGetPhysicalDeviceFormatProperties(vk->getPhysicalDevice(), + VK_FORMAT_ASTC_4x4_UNORM_BLOCK, &format_properties); + g_supports_astc_4x4 = format_properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; uint32_t extension_count; vkEnumerateDeviceExtensionProperties(vk->getPhysicalDevice(), NULL, @@ -190,6 +196,9 @@ void GEVulkanFeatures::printStats() os::Printer::log( "Vulkan supports s3 texture compression (bc3, dxt5)", g_supports_s3tc_bc3 ? "true" : "false"); + os::Printer::log( + "Vulkan supports adaptive scalable texture compression (4x4 block)", + supportsASTC4x4() ? "true" : "false"); os::Printer::log( "Vulkan descriptor indexes can be dynamically non-uniform", g_supports_non_uniform_indexing ? "true" : "false"); @@ -275,4 +284,10 @@ bool GEVulkanFeatures::supportsS3TCBC3() return g_supports_s3tc_bc3; } // supportsS3TCBC3 +// ---------------------------------------------------------------------------- +bool GEVulkanFeatures::supportsASTC4x4() +{ + return g_supports_astc_4x4 && GECompressorASTC4x4::loaded(); +} // supportsASTC4x4 + } diff --git a/lib/graphics_engine/src/ge_vulkan_features.hpp b/lib/graphics_engine/src/ge_vulkan_features.hpp index 656ee1347..40afbf6ba 100644 --- a/lib/graphics_engine/src/ge_vulkan_features.hpp +++ b/lib/graphics_engine/src/ge_vulkan_features.hpp @@ -36,6 +36,8 @@ bool supportsBaseVertexRendering(); bool supportsComputeInMainQueue(); // ---------------------------------------------------------------------------- bool supportsS3TCBC3(); +// ---------------------------------------------------------------------------- +bool supportsASTC4x4(); }; // GEVulkanFeatures } diff --git a/lib/graphics_engine/src/ge_vulkan_texture.cpp b/lib/graphics_engine/src/ge_vulkan_texture.cpp index 241b0de3c..467db3d80 100644 --- a/lib/graphics_engine/src/ge_vulkan_texture.cpp +++ b/lib/graphics_engine/src/ge_vulkan_texture.cpp @@ -2,6 +2,7 @@ #include "ge_main.hpp" #include "ge_mipmap_generator.hpp" +#include "ge_compressor_astc_4x4.hpp" #include "ge_compressor_s3tc_bc3.hpp" #include "ge_texture.hpp" #include "ge_vulkan_command_loader.hpp" @@ -123,7 +124,15 @@ bool GEVulkanTexture::createTextureImage(uint8_t* texture_data, const bool normal_map = (std::string(NamedPath.getPtr()).find( "_Normal.") != std::string::npos); bool texture_compression = getGEConfig()->m_texture_compression; - if (texture_compression && GEVulkanFeatures::supportsS3TCBC3()) + if (texture_compression && GEVulkanFeatures::supportsASTC4x4()) + { + image_size = get4x4CompressedTextureSize(m_size.Width, + m_size.Height); + m_internal_format = VK_FORMAT_ASTC_4x4_UNORM_BLOCK; + mipmap_generator = new GECompressorASTC4x4(texture_data, channels, + m_size, normal_map); + } + else if (texture_compression && GEVulkanFeatures::supportsS3TCBC3()) { image_size = get4x4CompressedTextureSize(m_size.Width, m_size.Height);