Add GECompressorASTC4x4

This commit is contained in:
Benau 2022-08-07 15:33:54 +08:00
parent 93dc6ed770
commit d7390a1824
11 changed files with 249 additions and 2 deletions

1
.gitignore vendored
View File

@ -89,5 +89,6 @@ lib/openssl
lib/harfbuzz
lib/sdl2
lib/mbedtls
lib/astc-encoder
.DS_Store

View File

@ -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 "")

View File

@ -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 <astcenc.h>
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()

View File

@ -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 <algorithm>
#include <cassert>
#include <cstdio>
#include <vector>
#ifdef ENABLE_LIBASTCENC
#include <astcenc.h>
#include <SDL_cpuinfo.h>
#endif
namespace GE
{
// ============================================================================
#ifdef ENABLE_LIBASTCENC
namespace GEVulkanFeatures
{
extern bool g_supports_astc_4x4;
}
std::vector<astcenc_context*> 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<irr::u32>& 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<GEImageLevel> 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
}

View File

@ -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<irr::u32>& size,
bool normal_map);
// ------------------------------------------------------------------------
~GECompressorASTC4x4() { delete [] m_compressed_data; }
}; // GEASTCCompressor
}
#endif

View File

@ -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()
{

View File

@ -19,6 +19,8 @@ bool multiThreadingEnabled();
// ----------------------------------------------------------------------------
bool isUsingMultiThreadingNow();
// ----------------------------------------------------------------------------
unsigned getLoaderCount();
// ----------------------------------------------------------------------------
int getLoaderId();
// ----------------------------------------------------------------------------
VkCommandPool getCurrentCommandPool();

View File

@ -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();

View File

@ -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
}

View File

@ -36,6 +36,8 @@ bool supportsBaseVertexRendering();
bool supportsComputeInMainQueue();
// ----------------------------------------------------------------------------
bool supportsS3TCBC3();
// ----------------------------------------------------------------------------
bool supportsASTC4x4();
}; // GEVulkanFeatures
}

View File

@ -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);