SpiecsEngine
 
Loading...
Searching...
No Matches
Transcoder.cpp
Go to the documentation of this file.
1/**
2* @file Transcoder.cpp.
3* @brief The Transcoder Class Implementation.
4* @author Spices.
5*/
6
7#include "Pchheader.h"
8#include "Transcoder.h"
9#include "Core/Timer/ScopeTimer.h"
10#include "Render/Vulkan/VulkanDevice.h"
11#include "Render/Vulkan/VulkanRenderBackend.h"
12
13#include <../external/basisu/transcoder/basisu_transcoder.h>
14#include <ktx.h>
15#include <../lib/vkformat_enum.h>
16#include <stb_image.h>
17
18namespace Spices {
19
20#define KTX_CHECK(expr)
21 {
22 if (expr == KTX_SUCCESS) {}
23 else
24 {
25 std::stringstream ss;
26 ss << "Assert Failed \n At File: " << __FILE__ << " \n At Line: " << __LINE__ << "\n ";
27 SPICES_CORE_ERROR(ss.str());
28 }
29 }
30
32 {
34
35 /**
36 * @brief The encoder already initializes the transcoder, but if you haven't initialized the encoder you MUST call this function to initialize the transcoder.
37 */
38 basist::basisu_transcoder_init();
39 }
40
41 ktxTexture2* Transcoder::CreateKTX2Texture(int& width, int& height)
42 {
44
45 /**
46 * @brief Instance a ktxTextureCreateInfo.
47 */
48 ktxTextureCreateInfo createInfo;
49 createInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
50 createInfo.baseWidth = width;
51 createInfo.baseHeight = height;
52 createInfo.baseDepth = 1;
53 createInfo.numDimensions = 2;
54 createInfo.numLevels = static_cast<uint32_t>(std::floor(std::log2(std::max(width, height)))) + 1; // Must be 1 if enable generateMipmaps.
55 createInfo.numLayers = 1;
56 createInfo.numFaces = 1;
57 createInfo.isArray = KTX_FALSE;
58 createInfo.generateMipmaps = KTX_FALSE; // Must be false before compress.
59
60 ktxTexture2* texture;
61
62 // Call ktxTexture1_Create to create a KTX texture.
63 KTX_CHECK(ktxTexture2_Create(&createInfo, KTX_TEXTURE_CREATE_ALLOC_STORAGE, &texture))
64
65 return texture;
66 }
67
68 bool Transcoder::WriteData(ktxTexture2* texture, uint32_t mipLevel, const unsigned char* data, uint32_t size)
69 {
71
72 KTX_CHECK(ktxTexture_SetImageFromMemory(ktxTexture(texture), mipLevel, 0, 0, data, size))
73
74 return true;
75 }
76
77 bool Transcoder::SaveToDisk(ktxTexture2* texture, const std::string& filePath)
78 {
80
81 /**
82 * @brief Instance a ktxBasisParams.
83 * etc1s: unlosslessly compressed, host memory << device memory.
84 * uastc: losslessly compressed, host memory == device memory.
85 */
86 ktxBasisParams params{0};
87 params.structSize = sizeof(params);
88 params.uastc = KTX_TRUE;
89 params.verbose = KTX_FALSE;
90 params.noSSE = KTX_TRUE;
91
92 // etc1s
93 params.threadCount = std::thread::hardware_concurrency();
94 params.compressionLevel = 0;
95 params.qualityLevel = 128;
96
97 // uastc
98 params.uastcFlags = KTX_PACK_UASTC_LEVEL_FASTEST;
99 params.uastcRDO = KTX_TRUE;
100 params.uastcRDONoMultithreading = KTX_TRUE;
101
102 /**
103 * @brief Set other BasisLZ / ETC1S or UASTC params to change default quality settings.
104 */
105 KTX_CHECK(ktxTexture2_CompressBasisEx(texture, &params))
106
107 /**
108 * @brief Write to disk.
109 */
110 std::filesystem::create_directories(std::filesystem::path(filePath).parent_path());
111 ktxTexture_WriteToNamedFile(ktxTexture(texture), filePath.c_str());
112 ktxTexture_Destroy(ktxTexture(texture));
113
114#if 0 // Disable auto mipmaps, we will manually generate mipmaps.
115
116 /**
117 * @brief Load ktx file and set generateMipmaps to true.
118 */
119 KTX_CHECK(ktxTexture2_CreateFromNamedFile(filePath.c_str(), KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, &texture))
120 texture->generateMipmaps = KTX_TRUE;
121
122 /**
123 * @brief ReWrite angin.
124 */
125 ktxTexture_WriteToNamedFile(ktxTexture(texture), filePath.c_str());
126 ktxTexture_Destroy(ktxTexture(texture));
127
128#endif
129
130 return true;
131 }
132
133 bool Transcoder::LoadFromKTX(const std::string& filePath, ktxTexture2*& texture)
134 {
136
137 KTX_CHECK(ktxTexture2_CreateFromNamedFile(filePath.c_str(), KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, &texture))
138
139 if (ktxTexture2_NeedsTranscoding(texture))
140 {
141 ktx_transcode_fmt_e tf = GetAvailableTargetFormats();
142
143 khr_df_model_e colorModel = ktxTexture2_GetColorModel_e(texture);
144
145 KTX_CHECK(ktxTexture2_TranscodeBasis(texture, tf, 0))
146 }
147
148#if 0
149
150 /**
151 * @brief Those method use bitimage to create mipmap, which is not suuported by compress format.
152 */
153 ktxVulkanDeviceInfo vdi{};
154 VulkanState& state = VulkanRenderBackend::GetState();
155
156 KTX_CHECK(ktxVulkanDeviceInfo_Construct(
157 &vdi,
158 state.m_PhysicalDevice,
159 state.m_Device,
160 state.m_GraphicQueue,
161 state.m_GraphicCommandPool,
162 nullptr
163 ))
164
165 KTX_CHECK(ktxTexture2_VkUploadEx(
166 texture ,
167 &vdi ,
168 vkTexture ,
169 VK_IMAGE_TILING_OPTIMAL ,
170 VK_IMAGE_USAGE_SAMPLED_BIT ,
171 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
172 ))
173
174 /**
175 * @brief Get Texture MetaData.
176 */
177 char* pValue;
178 uint32_t valueLen;
179 KTX_CHECK(ktxHashList_FindValue(
180 &texture->kvDataHead ,
181 KTX_ORIENTATION_KEY ,
182 &valueLen ,
183 (void**)&pValue
184 ))
185 {
186 char s, t;
187
188 if (sscanf(pValue, KTX_ORIENTATION2_FMT, &s, &t) == 2)
189 {
190
191 }
192 }
193
194 ktxTexture_Destroy(ktxTexture(texture));
195 ktxVulkanDeviceInfo_Destruct(&vdi);
196
197#endif
198
199 return true;
200 }
201
202 bool Transcoder::DestroyktxTexture2(ktxTexture2* texture)
203 {
205
206 ktxTexture_Destroy(ktxTexture(texture));
207
208 return true;
209 }
210
211 ktx_size_t Transcoder::GetMipmapOffset(ktxTexture2* texture, uint32_t mipLevel)
212 {
214
215 ktx_size_t offset;
216 KTX_CHECK(ktxTexture_GetImageOffset((ktxTexture*)texture, mipLevel, 0, 0, &offset))
217
218 return offset;
219 }
220
221 bool Transcoder::FormatSupported(VkFormat format)
222 {
224
225 VkFormatProperties properties{};
226
228 vkGetPhysicalDeviceFormatProperties(state.m_PhysicalDevice, format, &properties);
229
230
231 VkFormatFeatureFlags neededFeatures
232 = VK_FORMAT_FEATURE_BLIT_DST_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT;
233
234
235 return ((properties.optimalTilingFeatures & VK_FORMAT_FEATURE_TRANSFER_DST_BIT) &&
236 (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT));
237 }
238
239 ktx_transcode_fmt_e Transcoder::GetAvailableTargetFormats()
240 {
242
243 VkPhysicalDeviceFeatures feature = VulkanDevice::GetDeviceFeatures();
244
245 // Block compression
246 if (feature.textureCompressionBC)
247 {
248 // BC7 is the preferred block compression if available
249 if (FormatSupported(VK_FORMAT_BC7_SRGB_BLOCK))
250 {
251 return KTX_TTF_BC7_RGBA;
252 }
253
254 if (FormatSupported(VK_FORMAT_BC3_SRGB_BLOCK))
255 {
256 return KTX_TTF_BC3_RGBA;
257 }
258 }
259
260 // Adaptive scalable texture compression
261 if (feature.textureCompressionASTC_LDR)
262 {
263 if (FormatSupported(VK_FORMAT_ASTC_4x4_SRGB_BLOCK))
264 {
265 return KTX_TTF_ASTC_4x4_RGBA;
266 }
267 }
268
269 // Ericsson texture compression
270 if (feature.textureCompressionETC2)
271 {
272 if (FormatSupported(VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK))
273 {
274 return KTX_TTF_ETC2_RGBA;
275 }
276 }
277
278 // PowerVR texture compression support needs to be checked via an extension
279 /*if (get_device().is_extension_supported(VK_IMG_FORMAT_PVRTC_EXTENSION_NAME))
280 {
281 if (FormatSupported(VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG))
282 {
283 return KTX_TTF_PVRTC1_4_RGBA;
284 }
285 }*/
286
287 // Always add uncompressed RGBA as a valid target
288 return KTX_TTF_RGBA32;
289 }
290}
#define SPICES_PROFILE_ZONE
#define KTX_CHECK(expr)
static void Init()
Init basisu.
Transcoder of Texture Container format and Transform format and GPU compress format.
Definition Transcoder.h:17
static VulkanState & GetState()
Get VulkanState in use.
This class defines the render backend behaves of Vulkan.
This struct contains all Vulkan object in used global.
Definition VulkanUtils.h:74