Skip to content

Commit d7390a1

Browse files
committed
Add GECompressorASTC4x4
1 parent 93dc6ed commit d7390a1

11 files changed

+249
-2
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,5 +89,6 @@ lib/openssl
8989
lib/harfbuzz
9090
lib/sdl2
9191
lib/mbedtls
92+
lib/astc-encoder
9293

9394
.DS_Store

cmake/Toolchain-ios-xcode.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ set(LIBSAMPLERATE_LIBRARY ${PROJECT_SOURCE_DIR}/dependencies\${EFFECTIVE_PLATFOR
5959
set(LIBSAMPLERATE_INCLUDEDIR ${PROJECT_SOURCE_DIR}/dependencies-iphoneos/include CACHE STRING "")
6060
set(MOLTENVK_LIBRARY ${PROJECT_SOURCE_DIR}/dependencies\${EFFECTIVE_PLATFORM_NAME}/lib/libMoltenVK.a CACHE STRING "")
6161
set(VULKAN_INCLUDEDIR ${PROJECT_SOURCE_DIR}/dependencies-iphoneos/include CACHE STRING "")
62+
set(LIBASTCENC_LIBRARY ${PROJECT_SOURCE_DIR}/dependencies\${EFFECTIVE_PLATFORM_NAME}/lib/libastcenc.a CACHE STRING "")
63+
set(LIBASTCENC_INCLUDEDIR ${PROJECT_SOURCE_DIR}/dependencies-iphoneos/include CACHE STRING "")
6264

6365
# For universal iOS and simulator
6466
set(LIBRESOLV_LIBRARY -lresolv CACHE STRING "")

lib/graphics_engine/CMakeLists.txt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,42 @@
1+
# Distro package just use libastcenc.so, find it first
2+
find_library(LIBASTCENC_LIBRARY NAMES libastcenc astcenc astcenc-avx2-static astcenc-sse4.1-static astcenc-sse2-static astcenc-neon-static astcenc-native-static)
3+
find_path(LIBASTCENC_INCLUDEDIR NAMES astcenc.h PATHS)
4+
if (LIBASTCENC_LIBRARY AND LIBASTCENC_INCLUDEDIR)
5+
set(ENABLE_LIBASTCENC 1)
6+
add_definitions(-DENABLE_LIBASTCENC)
7+
include_directories("${LIBASTCENC_INCLUDEDIR}")
8+
message(STATUS "Use libastcenc: ${LIBASTCENC_LIBRARY}")
9+
10+
if (NOT MSVC)
11+
set(CMAKE_REQUIRED_FLAGS "-std=c++11")
12+
endif()
13+
set(CMAKE_REQUIRED_INCLUDES ${LIBASTCENC_INCLUDEDIR})
14+
set(CMAKE_REQUIRED_LIBRARIES ${LIBASTCENC_LIBRARY})
15+
include(CheckCXXSourceCompiles)
16+
check_cxx_source_compiles("
17+
#define ASTCENC_DYNAMIC_LIBRARY 1
18+
#include <astcenc.h>
19+
int main()
20+
{
21+
astcenc_context_free(NULL);
22+
return 0;
23+
}
24+
" ASTCENC_DLL)
25+
if (NOT MSVC)
26+
unset(CMAKE_REQUIRED_FLAGS)
27+
endif()
28+
unset(CMAKE_REQUIRED_INCLUDES)
29+
unset(CMAKE_REQUIRED_LIBRARIES)
30+
if (ASTCENC_DLL)
31+
message(STATUS "libastcenc: -DASTCENC_DYNAMIC_LIBRARY required")
32+
add_definitions(-DASTCENC_DYNAMIC_LIBRARY)
33+
endif()
34+
35+
else()
36+
message(WARNING "Missing astc-encoder for astc support, "
37+
"visit https://github.com/ARM-software/astc-encoder for details")
38+
endif()
39+
140
include_directories("${PROJECT_SOURCE_DIR}/lib/graphics_engine/include")
241
include_directories("${PROJECT_SOURCE_DIR}/lib/graphics_utils")
342
include_directories("${PROJECT_SOURCE_DIR}/lib/irrlicht/include")
@@ -24,6 +63,7 @@ endif()
2463

2564
set(GE_SOURCES
2665
src/gl.c
66+
src/ge_compressor_astc_4x4.cpp
2767
src/ge_compressor_s3tc_bc3.cpp
2868
src/ge_culling_tool.cpp
2969
src/ge_dx9_texture.cpp
@@ -58,3 +98,7 @@ endif()
5898
add_library(graphics_engine STATIC ${GE_SOURCES})
5999

60100
target_link_libraries(graphics_engine ${SQUISH_LIBRARY})
101+
102+
if(ENABLE_LIBASTCENC)
103+
target_link_libraries(graphics_engine ${LIBASTCENC_LIBRARY})
104+
endif()
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
#include "ge_compressor_astc_4x4.hpp"
2+
3+
#include "ge_main.hpp"
4+
#include "ge_vulkan_command_loader.hpp"
5+
#include "ge_vulkan_features.hpp"
6+
7+
#include <algorithm>
8+
#include <cassert>
9+
#include <cstdio>
10+
#include <vector>
11+
12+
#ifdef ENABLE_LIBASTCENC
13+
#include <astcenc.h>
14+
#include <SDL_cpuinfo.h>
15+
#endif
16+
17+
namespace GE
18+
{
19+
// ============================================================================
20+
#ifdef ENABLE_LIBASTCENC
21+
namespace GEVulkanFeatures
22+
{
23+
extern bool g_supports_astc_4x4;
24+
}
25+
26+
std::vector<astcenc_context*> g_astc_contexts;
27+
#endif
28+
// ============================================================================
29+
void GECompressorASTC4x4::init()
30+
{
31+
#ifdef ENABLE_LIBASTCENC
32+
if (!GEVulkanFeatures::g_supports_astc_4x4)
33+
return;
34+
35+
// Check for neon existence because libastcenc doesn't do that
36+
// x86 will exit in astcenc_context_alloc if sse2 / sse4.1 is not supported
37+
#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined (_M_ARM64)
38+
if (SDL_HasNEON() == SDL_FALSE)
39+
return;
40+
#endif
41+
42+
astcenc_config cfg = {};
43+
float quality = ASTCENC_PRE_FASTEST;
44+
if (astcenc_config_init(ASTCENC_PRF_LDR, 4, 4, 1, quality, 0, &cfg) !=
45+
ASTCENC_SUCCESS)
46+
return;
47+
48+
for (unsigned i = 0; i < GEVulkanCommandLoader::getLoaderCount(); i++)
49+
{
50+
astcenc_context* context = NULL;
51+
if (astcenc_context_alloc(&cfg, 1, &context) != ASTCENC_SUCCESS)
52+
{
53+
destroy();
54+
return;
55+
}
56+
g_astc_contexts.push_back(context);
57+
}
58+
#endif
59+
} // init
60+
61+
// ============================================================================
62+
void GECompressorASTC4x4::destroy()
63+
{
64+
#ifdef ENABLE_LIBASTCENC
65+
for (astcenc_context* context : g_astc_contexts)
66+
astcenc_context_free(context);
67+
g_astc_contexts.clear();
68+
#endif
69+
} // destroy
70+
71+
// ============================================================================
72+
bool GECompressorASTC4x4::loaded()
73+
{
74+
#ifdef ENABLE_LIBASTCENC
75+
return !g_astc_contexts.empty();
76+
#else
77+
return false;
78+
#endif
79+
} // loaded
80+
81+
// ----------------------------------------------------------------------------
82+
GECompressorASTC4x4::GECompressorASTC4x4(uint8_t* texture, unsigned channels,
83+
const irr::core::dimension2d<irr::u32>& size,
84+
bool normal_map)
85+
: GEMipmapGenerator(texture, channels, size, normal_map)
86+
{
87+
#ifdef ENABLE_LIBASTCENC
88+
assert(channels == 4);
89+
size_t total_size = 0;
90+
m_mipmap_sizes = 0;
91+
for (unsigned i = 0; i < m_levels.size(); i++)
92+
{
93+
GEImageLevel& level = m_levels[i];
94+
unsigned cur_size = get4x4CompressedTextureSize(level.m_dim.Width,
95+
level.m_dim.Height);
96+
total_size += cur_size;
97+
if (i > 0)
98+
m_mipmap_sizes += cur_size;
99+
}
100+
101+
std::vector<GEImageLevel> compressed_levels;
102+
m_compressed_data = new uint8_t[total_size];
103+
uint8_t* cur_offset = m_compressed_data;
104+
105+
for (GEImageLevel& level : m_levels)
106+
{
107+
astcenc_image img;
108+
img.dim_x = level.m_dim.Width;
109+
img.dim_y = level.m_dim.Height;
110+
img.dim_z = 1;
111+
img.data_type = ASTCENC_TYPE_U8;
112+
img.data = &level.m_data;
113+
114+
astcenc_swizzle swizzle;
115+
swizzle.r = ASTCENC_SWZ_R;
116+
swizzle.g = ASTCENC_SWZ_G;
117+
swizzle.b = ASTCENC_SWZ_B;
118+
swizzle.a = ASTCENC_SWZ_A;
119+
120+
unsigned cur_size = get4x4CompressedTextureSize(level.m_dim.Width,
121+
level.m_dim.Height);
122+
if (astcenc_compress_image(
123+
g_astc_contexts[GEVulkanCommandLoader::getLoaderId()], &img,
124+
&swizzle, cur_offset, cur_size, 0) != ASTCENC_SUCCESS)
125+
printf("astcenc_compress_image failed!\n");
126+
compressed_levels.push_back({ level.m_dim, cur_size, cur_offset });
127+
cur_offset += cur_size;
128+
}
129+
freeMipmapCascade();
130+
std::swap(compressed_levels, m_levels);
131+
#endif
132+
} // GECompressorASTC4x4
133+
134+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#ifndef HEADER_GE_ASTC_COMPRESSOR_HPP
2+
#define HEADER_GE_ASTC_COMPRESSOR_HPP
3+
4+
#include "ge_mipmap_generator.hpp"
5+
6+
namespace GE
7+
{
8+
class GECompressorASTC4x4 : public GEMipmapGenerator
9+
{
10+
private:
11+
uint8_t* m_compressed_data;
12+
public:
13+
// ------------------------------------------------------------------------
14+
static void init();
15+
// ------------------------------------------------------------------------
16+
static void destroy();
17+
// ------------------------------------------------------------------------
18+
static bool loaded();
19+
// ------------------------------------------------------------------------
20+
GECompressorASTC4x4(uint8_t* texture, unsigned channels,
21+
const irr::core::dimension2d<irr::u32>& size,
22+
bool normal_map);
23+
// ------------------------------------------------------------------------
24+
~GECompressorASTC4x4() { delete [] m_compressed_data; }
25+
}; // GEASTCCompressor
26+
27+
}
28+
29+
#endif

lib/graphics_engine/src/ge_vulkan_command_loader.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ void GEVulkanCommandLoader::init(GEVulkanDriver* vk)
8484
}
8585
}
8686

87-
g_loader_count.store(thread_count - 1);
87+
g_loader_count.store(thread_count);
8888
for (unsigned i = 0; i < thread_count - 1; i++)
8989
{
9090
g_loaders.emplace_back(
@@ -153,6 +153,12 @@ bool GEVulkanCommandLoader::isUsingMultiThreadingNow()
153153
return g_loader_id != 0;
154154
} // isUsingMultiThreadingNow
155155

156+
// ----------------------------------------------------------------------------
157+
unsigned GEVulkanCommandLoader::getLoaderCount()
158+
{
159+
return g_loader_count.load();
160+
} // getLoaderCount
161+
156162
// ----------------------------------------------------------------------------
157163
int GEVulkanCommandLoader::getLoaderId()
158164
{

lib/graphics_engine/src/ge_vulkan_command_loader.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ bool multiThreadingEnabled();
1919
// ----------------------------------------------------------------------------
2020
bool isUsingMultiThreadingNow();
2121
// ----------------------------------------------------------------------------
22+
unsigned getLoaderCount();
23+
// ----------------------------------------------------------------------------
2224
int getLoaderId();
2325
// ----------------------------------------------------------------------------
2426
VkCommandPool getCurrentCommandPool();

lib/graphics_engine/src/ge_vulkan_driver.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "ge_vulkan_driver.hpp"
22

3+
#include "ge_compressor_astc_4x4.hpp"
34
#include "ge_main.hpp"
45

56
#include "ge_vulkan_2d_renderer.hpp"
@@ -632,6 +633,7 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
632633
GEVulkanShaderManager::getSamplerSize(),
633634
GEVulkanShaderManager::getMeshTextureLayer(),
634635
GEVulkanFeatures::supportsBindMeshTexturesAtOnce());
636+
GECompressorASTC4x4::init();
635637
GEVulkanFeatures::printStats();
636638
}
637639
catch (std::exception& e)
@@ -651,6 +653,7 @@ GEVulkanDriver::~GEVulkanDriver()
651653
// ----------------------------------------------------------------------------
652654
void GEVulkanDriver::destroyVulkan()
653655
{
656+
GECompressorASTC4x4::destroy();
654657
if (m_depth_texture)
655658
{
656659
m_depth_texture->drop();

lib/graphics_engine/src/ge_vulkan_features.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "ge_vulkan_features.hpp"
22

3+
#include "ge_compressor_astc_4x4.hpp"
34
#include "ge_vulkan_driver.hpp"
45
#include "ge_vulkan_shader_manager.hpp"
56

@@ -27,6 +28,7 @@ bool g_supports_multi_draw_indirect = false;
2728
bool g_supports_base_vertex_rendering = true;
2829
bool g_supports_compute_in_main_queue = false;
2930
bool g_supports_s3tc_bc3 = false;
31+
bool g_supports_astc_4x4 = false;
3032
} // GEVulkanFeatures
3133

3234
// ============================================================================
@@ -70,6 +72,10 @@ void GEVulkanFeatures::init(GEVulkanDriver* vk)
7072
vkGetPhysicalDeviceFormatProperties(vk->getPhysicalDevice(),
7173
VK_FORMAT_BC3_UNORM_BLOCK, &format_properties);
7274
g_supports_s3tc_bc3 = format_properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
75+
format_properties = {};
76+
vkGetPhysicalDeviceFormatProperties(vk->getPhysicalDevice(),
77+
VK_FORMAT_ASTC_4x4_UNORM_BLOCK, &format_properties);
78+
g_supports_astc_4x4 = format_properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
7379

7480
uint32_t extension_count;
7581
vkEnumerateDeviceExtensionProperties(vk->getPhysicalDevice(), NULL,
@@ -190,6 +196,9 @@ void GEVulkanFeatures::printStats()
190196
os::Printer::log(
191197
"Vulkan supports s3 texture compression (bc3, dxt5)",
192198
g_supports_s3tc_bc3 ? "true" : "false");
199+
os::Printer::log(
200+
"Vulkan supports adaptive scalable texture compression (4x4 block)",
201+
supportsASTC4x4() ? "true" : "false");
193202
os::Printer::log(
194203
"Vulkan descriptor indexes can be dynamically non-uniform",
195204
g_supports_non_uniform_indexing ? "true" : "false");
@@ -275,4 +284,10 @@ bool GEVulkanFeatures::supportsS3TCBC3()
275284
return g_supports_s3tc_bc3;
276285
} // supportsS3TCBC3
277286

287+
// ----------------------------------------------------------------------------
288+
bool GEVulkanFeatures::supportsASTC4x4()
289+
{
290+
return g_supports_astc_4x4 && GECompressorASTC4x4::loaded();
291+
} // supportsASTC4x4
292+
278293
}

lib/graphics_engine/src/ge_vulkan_features.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ bool supportsBaseVertexRendering();
3636
bool supportsComputeInMainQueue();
3737
// ----------------------------------------------------------------------------
3838
bool supportsS3TCBC3();
39+
// ----------------------------------------------------------------------------
40+
bool supportsASTC4x4();
3941
}; // GEVulkanFeatures
4042

4143
}

0 commit comments

Comments
 (0)