/src/astc-encoder/Source/astcenc_image.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // ---------------------------------------------------------------------------- |
3 | | // Copyright 2011-2026 Arm Limited |
4 | | // |
5 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
6 | | // use this file except in compliance with the License. You may obtain a copy |
7 | | // of the License at: |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, software |
12 | | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
13 | | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
14 | | // License for the specific language governing permissions and limitations |
15 | | // under the License. |
16 | | // ---------------------------------------------------------------------------- |
17 | | |
18 | | /** |
19 | | * @brief Functions for creating in-memory ASTC image structures. |
20 | | */ |
21 | | |
22 | | #include <cassert> |
23 | | #include <cstring> |
24 | | |
25 | | #include "astcenc_internal.h" |
26 | | |
27 | | /** |
28 | | * @brief Loader pipeline function type for data fetch from memory. |
29 | | */ |
30 | | using pixel_loader = vfloat4(*)(const void*, size_t); |
31 | | |
32 | | /** |
33 | | * @brief Loader pipeline function type for swizzling data in a vector. |
34 | | */ |
35 | | using pixel_swizzler = vfloat4(*)(vfloat4, const astcenc_swizzle&); |
36 | | |
37 | | /** |
38 | | * @brief Loader pipeline function type for converting data in a vector to LNS. |
39 | | */ |
40 | | using pixel_converter = vfloat4(*)(vfloat4, vmask4); |
41 | | |
42 | | /** |
43 | | * @brief Load an 8-bit UNORM texel from a data array. |
44 | | * |
45 | | * @param data The data pointer. |
46 | | * @param base_offset The index offset to the start of the pixel. |
47 | | */ |
48 | | static vfloat4 load_texel_u8( |
49 | | const void* data, |
50 | | size_t base_offset |
51 | 22.8k | ) { |
52 | 22.8k | const uint8_t* data8 = static_cast<const uint8_t*>(data); |
53 | 22.8k | return int_to_float(vint4(data8 + base_offset)) / 255.0f; |
54 | 22.8k | } |
55 | | |
56 | | /** |
57 | | * @brief Load a 16-bit fp16 texel from a data array. |
58 | | * |
59 | | * @param data The data pointer. |
60 | | * @param base_offset The index offset to the start of the pixel. |
61 | | */ |
62 | | static vfloat4 load_texel_f16( |
63 | | const void* data, |
64 | | size_t base_offset |
65 | 0 | ) { |
66 | 0 | const uint16_t* data16 = static_cast<const uint16_t*>(data); |
67 | 0 | int r = data16[base_offset ]; |
68 | 0 | int g = data16[base_offset + 1]; |
69 | 0 | int b = data16[base_offset + 2]; |
70 | 0 | int a = data16[base_offset + 3]; |
71 | 0 | return float16_to_float(vint4(r, g, b, a)); |
72 | 0 | } |
73 | | |
74 | | /** |
75 | | * @brief Load a 32-bit float texel from a data array. |
76 | | * |
77 | | * @param data The data pointer. |
78 | | * @param base_offset The index offset to the start of the pixel. |
79 | | */ |
80 | | static vfloat4 load_texel_f32( |
81 | | const void* data, |
82 | | size_t base_offset |
83 | 0 | ) { |
84 | 0 | const float* data32 = static_cast<const float*>(data); |
85 | 0 | return vfloat4(data32 + base_offset); |
86 | 0 | } |
87 | | |
88 | | /** |
89 | | * @brief Dummy no-op swizzle function. |
90 | | * |
91 | | * @param data The source RGBA vector to swizzle. |
92 | | * @param swz The swizzle to use. |
93 | | */ |
94 | | static vfloat4 swz_texel_skip( |
95 | | vfloat4 data, |
96 | | const astcenc_swizzle& swz |
97 | 22.8k | ) { |
98 | 22.8k | (void)swz; |
99 | 22.8k | return data; |
100 | 22.8k | } |
101 | | |
102 | | /** |
103 | | * @brief Swizzle a texel into a new arrangement. |
104 | | * |
105 | | * @param data The source RGBA vector to swizzle. |
106 | | * @param swz The swizzle to use. |
107 | | */ |
108 | | static vfloat4 swz_texel( |
109 | | vfloat4 data, |
110 | | const astcenc_swizzle& swz |
111 | 0 | ) { |
112 | 0 | ASTCENC_ALIGNAS float datas[6]; |
113 | |
|
114 | 0 | storea(data, datas); |
115 | 0 | datas[ASTCENC_SWZ_0] = 0.0f; |
116 | 0 | datas[ASTCENC_SWZ_1] = 1.0f; |
117 | |
|
118 | 0 | return vfloat4(datas[swz.r], datas[swz.g], datas[swz.b], datas[swz.a]); |
119 | 0 | } |
120 | | |
121 | | /** |
122 | | * @brief Encode a texel that is entirely LDR linear. |
123 | | * |
124 | | * Out-of-range inputs will be clamped to the valid UNORM range. |
125 | | * |
126 | | * @param data The RGBA data to encode. |
127 | | * @param lns_mask The mask for the HDR channels that need LNS encoding. |
128 | | */ |
129 | | static vfloat4 encode_texel_unorm( |
130 | | vfloat4 data, |
131 | | vmask4 lns_mask |
132 | 22.8k | ) { |
133 | 22.8k | (void)lns_mask; |
134 | 22.8k | vfloat4 raw_value = data * 65535.0f; |
135 | | |
136 | | // Unorm data must be in 0-1 range, so clamp because data can come from an |
137 | | // unconstrained float. This will replace NaNs with zero. |
138 | 22.8k | return clamp(0.0f, 65535.0f, raw_value); |
139 | 22.8k | } |
140 | | |
141 | | /** |
142 | | * @brief Encode a texel that includes at least some HDR LNS texels. |
143 | | * |
144 | | * Out-of-range inputs will be clamped to the valid LNS or UNORM range, |
145 | | * depending on @c lns_mask. |
146 | | * |
147 | | * @param data The RGBA data to encode. |
148 | | * @param lns_mask The mask for the HDR channels that need LNS encoding. |
149 | | */ |
150 | | static vfloat4 encode_texel_lns( |
151 | | vfloat4 data, |
152 | | vmask4 lns_mask |
153 | 22.8k | ) { |
154 | 22.8k | vfloat4 datav_unorm = encode_texel_unorm(data, lns_mask); |
155 | | |
156 | | // Out-of-range inputs are clamped inside float_to_lns |
157 | 22.8k | vfloat4 datav_lns = float_to_lns(data); |
158 | 22.8k | return select(datav_unorm, datav_lns, lns_mask); |
159 | 22.8k | } |
160 | | |
161 | | /* See header for documentation. */ |
162 | | void load_image_block( |
163 | | astcenc_profile decode_mode, |
164 | | const astcenc_image& img, |
165 | | image_block& blk, |
166 | | const block_size_descriptor& bsd, |
167 | | size_t pos_x, |
168 | | size_t pos_y, |
169 | | size_t pos_z, |
170 | | const astcenc_swizzle& swz |
171 | 972 | ) { |
172 | 972 | size_t size_x = img.dim_x; |
173 | 972 | size_t size_y = img.dim_y; |
174 | 972 | size_t size_z = img.dim_z; |
175 | | |
176 | 972 | blk.pos_x = pos_x; |
177 | 972 | blk.pos_y = pos_y; |
178 | 972 | blk.pos_z = pos_z; |
179 | | |
180 | | // True if any non-identity swizzle |
181 | 972 | bool needs_swz = (swz.r != ASTCENC_SWZ_R) || (swz.g != ASTCENC_SWZ_G) || |
182 | 972 | (swz.b != ASTCENC_SWZ_B) || (swz.a != ASTCENC_SWZ_A); |
183 | | |
184 | 972 | vfloat4 data_min(1e38f); |
185 | 972 | vfloat4 data_mean(0.0f); |
186 | 972 | vfloat4 data_mean_scale(1.0f / static_cast<float>(bsd.texel_count)); |
187 | 972 | vfloat4 data_max(-1e38f); |
188 | 972 | vmask4 grayscalev(true); |
189 | 972 | size_t idx = 0; |
190 | | |
191 | | // This works because we impose the same choice everywhere during encode |
192 | 972 | uint8_t rgb_lns = (decode_mode == ASTCENC_PRF_HDR) || |
193 | 972 | (decode_mode == ASTCENC_PRF_HDR_RGB_LDR_A) ? 1 : 0; |
194 | 972 | uint8_t a_lns = decode_mode == ASTCENC_PRF_HDR ? 1 : 0; |
195 | 972 | vint4 use_lns(rgb_lns, rgb_lns, rgb_lns, a_lns); |
196 | 972 | vmask4 lns_mask = use_lns != vint4::zero(); |
197 | | |
198 | | // Set up the function pointers for loading pipeline as needed |
199 | 972 | pixel_loader loader = load_texel_u8; |
200 | 972 | if (img.data_type == ASTCENC_TYPE_F16) |
201 | 0 | { |
202 | 0 | loader = load_texel_f16; |
203 | 0 | } |
204 | 972 | else if (img.data_type == ASTCENC_TYPE_F32) |
205 | 0 | { |
206 | 0 | loader = load_texel_f32; |
207 | 0 | } |
208 | | |
209 | 972 | pixel_swizzler swizzler = swz_texel_skip; |
210 | 972 | if (needs_swz) |
211 | 0 | { |
212 | 0 | swizzler = swz_texel; |
213 | 0 | } |
214 | | |
215 | 972 | pixel_converter converter = encode_texel_unorm; |
216 | 972 | if (any(lns_mask)) |
217 | 972 | { |
218 | 972 | converter = encode_texel_lns; |
219 | 972 | } |
220 | | |
221 | 1.94k | for (size_t z = 0; z < bsd.dim_z; z++) |
222 | 972 | { |
223 | 972 | size_t zi = astc::min(pos_z + z, size_z - 1); |
224 | 972 | void* plane = img.data[zi]; |
225 | | |
226 | 5.31k | for (size_t y = 0; y < bsd.dim_y; y++) |
227 | 4.33k | { |
228 | 4.33k | size_t yi = astc::min(pos_y + y, size_y - 1); |
229 | | |
230 | 27.1k | for (size_t x = 0; x < bsd.dim_x; x++) |
231 | 22.8k | { |
232 | 22.8k | size_t xi = astc::min(pos_x + x, size_x - 1); |
233 | | |
234 | 22.8k | vfloat4 datav = loader(plane, (4 * size_x * yi) + (4 * xi)); |
235 | 22.8k | datav = swizzler(datav, swz); |
236 | 22.8k | datav = converter(datav, lns_mask); |
237 | | |
238 | | // Compute block metadata |
239 | 22.8k | data_min = min(data_min, datav); |
240 | 22.8k | data_mean += datav * data_mean_scale; |
241 | 22.8k | data_max = max(data_max, datav); |
242 | | |
243 | 22.8k | grayscalev = grayscalev & (datav.swz<0,0,0,0>() == datav.swz<1,1,2,2>()); |
244 | | |
245 | 22.8k | blk.data_r[idx] = datav.lane<0>(); |
246 | 22.8k | blk.data_g[idx] = datav.lane<1>(); |
247 | 22.8k | blk.data_b[idx] = datav.lane<2>(); |
248 | 22.8k | blk.data_a[idx] = datav.lane<3>(); |
249 | | |
250 | 22.8k | blk.rgb_lns[idx] = rgb_lns; |
251 | 22.8k | blk.alpha_lns[idx] = a_lns; |
252 | | |
253 | 22.8k | idx++; |
254 | 22.8k | } |
255 | 4.33k | } |
256 | 972 | } |
257 | | |
258 | | // Reverse the encoding so we store origin block in the original format |
259 | 972 | vfloat4 data_enc = blk.texel(0); |
260 | 972 | vfloat4 data_enc_unorm = data_enc / 65535.0f; |
261 | 972 | vfloat4 data_enc_lns = vfloat4::zero(); |
262 | | |
263 | 972 | if (rgb_lns || a_lns) |
264 | 972 | { |
265 | 972 | data_enc_lns = float16_to_float(lns_to_sf16(float_to_int(data_enc))); |
266 | 972 | } |
267 | | |
268 | 972 | blk.origin_texel = select(data_enc_unorm, data_enc_lns, lns_mask); |
269 | | |
270 | | // Store block metadata |
271 | 972 | blk.data_min = data_min; |
272 | 972 | blk.data_mean = data_mean; |
273 | 972 | blk.data_max = data_max; |
274 | 972 | blk.grayscale = all(grayscalev); |
275 | 972 | } |
276 | | |
277 | | /* See header for documentation. */ |
278 | | void load_image_block_fast_ldr( |
279 | | astcenc_profile decode_mode, |
280 | | const astcenc_image& img, |
281 | | image_block& blk, |
282 | | const block_size_descriptor& bsd, |
283 | | size_t pos_x, |
284 | | size_t pos_y, |
285 | | size_t pos_z, |
286 | | const astcenc_swizzle& swz |
287 | 1.08k | ) { |
288 | 1.08k | (void)swz; |
289 | 1.08k | (void)decode_mode; |
290 | | |
291 | 1.08k | size_t size_x = img.dim_x; |
292 | 1.08k | size_t size_y = img.dim_y; |
293 | | |
294 | 1.08k | blk.pos_x = pos_x; |
295 | 1.08k | blk.pos_y = pos_y; |
296 | 1.08k | blk.pos_z = pos_z; |
297 | | |
298 | 1.08k | vfloat4 data_min(1e38f); |
299 | 1.08k | vfloat4 data_mean = vfloat4::zero(); |
300 | 1.08k | vfloat4 data_max(-1e38f); |
301 | 1.08k | vmask4 grayscalev(true); |
302 | 1.08k | size_t idx = 0; |
303 | | |
304 | 1.08k | const uint8_t* plane = static_cast<const uint8_t*>(img.data[0]); |
305 | 6.17k | for (size_t y = pos_y; y < pos_y + bsd.dim_y; y++) |
306 | 5.09k | { |
307 | 5.09k | size_t yi = astc::min(y, size_y - 1); |
308 | | |
309 | 33.7k | for (size_t x = pos_x; x < pos_x + bsd.dim_x; x++) |
310 | 28.6k | { |
311 | 28.6k | size_t xi = astc::min(x, size_x - 1); |
312 | | |
313 | 28.6k | vint4 datavi = vint4(plane + (4 * size_x * yi) + (4 * xi)); |
314 | 28.6k | vfloat4 datav = int_to_float(datavi) * (65535.0f / 255.0f); |
315 | | |
316 | | // Compute block metadata |
317 | 28.6k | data_min = min(data_min, datav); |
318 | 28.6k | data_mean += datav; |
319 | 28.6k | data_max = max(data_max, datav); |
320 | | |
321 | 28.6k | grayscalev = grayscalev & (datav.swz<0,0,0,0>() == datav.swz<1,1,2,2>()); |
322 | | |
323 | 28.6k | blk.data_r[idx] = datav.lane<0>(); |
324 | 28.6k | blk.data_g[idx] = datav.lane<1>(); |
325 | 28.6k | blk.data_b[idx] = datav.lane<2>(); |
326 | 28.6k | blk.data_a[idx] = datav.lane<3>(); |
327 | | |
328 | 28.6k | idx++; |
329 | 28.6k | } |
330 | 5.09k | } |
331 | | |
332 | | // Reverse the encoding so we store origin block in the original format |
333 | 1.08k | blk.origin_texel = blk.texel(0) / 65535.0f; |
334 | | |
335 | | // Store block metadata |
336 | 1.08k | blk.rgb_lns[0] = 0; |
337 | 1.08k | blk.alpha_lns[0] = 0; |
338 | 1.08k | blk.data_min = data_min; |
339 | 1.08k | blk.data_mean = data_mean / static_cast<float>(bsd.texel_count); |
340 | 1.08k | blk.data_max = data_max; |
341 | 1.08k | blk.grayscale = all(grayscalev); |
342 | 1.08k | } |
343 | | |
344 | | /* See header for documentation. */ |
345 | | void store_image_block( |
346 | | astcenc_image& img, |
347 | | const image_block& blk, |
348 | | const block_size_descriptor& bsd, |
349 | | size_t pos_x, |
350 | | size_t pos_y, |
351 | | size_t pos_z, |
352 | | const astcenc_swizzle& swz |
353 | 3.84k | ) { |
354 | 3.84k | size_t size_x = img.dim_x; |
355 | 3.84k | size_t start_x = pos_x; |
356 | 3.84k | size_t end_x = astc::min(size_x, pos_x + bsd.dim_x); |
357 | 3.84k | size_t count_x = end_x - start_x; |
358 | 3.84k | size_t nudge_x = bsd.dim_x - count_x; |
359 | | |
360 | 3.84k | size_t size_y = img.dim_y; |
361 | 3.84k | size_t start_y = pos_y; |
362 | 3.84k | size_t end_y = astc::min(size_y, pos_y + bsd.dim_y); |
363 | 3.84k | size_t count_y = end_y - start_y; |
364 | 3.84k | size_t nudge_y = (bsd.dim_y - count_y) * bsd.dim_x; |
365 | | |
366 | 3.84k | size_t size_z = img.dim_z; |
367 | 3.84k | size_t start_z = pos_z; |
368 | 3.84k | size_t end_z = astc::min(size_z, pos_z + bsd.dim_z); |
369 | | |
370 | 3.84k | size_t idx = 0; |
371 | | |
372 | | // True if any non-identity swizzle |
373 | 3.84k | bool needs_swz = (swz.r != ASTCENC_SWZ_R) || (swz.g != ASTCENC_SWZ_G) || |
374 | 3.84k | (swz.b != ASTCENC_SWZ_B) || (swz.a != ASTCENC_SWZ_A); |
375 | | |
376 | | // True if any swizzle uses Z reconstruct |
377 | 3.84k | bool needs_z = (swz.r == ASTCENC_SWZ_Z) || (swz.g == ASTCENC_SWZ_Z) || |
378 | 3.84k | (swz.b == ASTCENC_SWZ_Z) || (swz.a == ASTCENC_SWZ_Z); |
379 | | |
380 | 3.84k | if (img.data_type == ASTCENC_TYPE_U8) |
381 | 3.84k | { |
382 | 7.69k | for (size_t z = start_z; z < end_z; z++) |
383 | 3.84k | { |
384 | | // Fetch the image plane |
385 | 3.84k | uint8_t* data8 = static_cast<uint8_t*>(img.data[z]); |
386 | | |
387 | 33.0k | for (size_t y = start_y; y < end_y; y++) |
388 | 29.2k | { |
389 | 29.2k | uint8_t* data8_row = data8 + (4 * size_x * y) + (4 * start_x); |
390 | | |
391 | 107k | for (size_t x = 0; x < count_x; x += ASTCENC_SIMD_WIDTH) |
392 | 77.9k | { |
393 | 77.9k | size_t max_texels = ASTCENC_SIMD_WIDTH; |
394 | 77.9k | size_t used_texels = astc::min(count_x - x, max_texels); |
395 | | |
396 | | // Unaligned load as rows are not always SIMD_WIDTH long |
397 | 77.9k | vfloat data_r(blk.data_r + idx); |
398 | 77.9k | vfloat data_g(blk.data_g + idx); |
399 | 77.9k | vfloat data_b(blk.data_b + idx); |
400 | 77.9k | vfloat data_a(blk.data_a + idx); |
401 | | |
402 | | // Clamp values to [0.0, 1.0] range before unorm conversion |
403 | | // - Values > 1.0 are possible for all HDR blocks |
404 | | // - Values < 0.0 are possible for HDR void-extent blocks |
405 | 77.9k | vint data_ri = float_to_int_rtn(clampzo(data_r) * 255.0f); |
406 | 77.9k | vint data_gi = float_to_int_rtn(clampzo(data_g) * 255.0f); |
407 | 77.9k | vint data_bi = float_to_int_rtn(clampzo(data_b) * 255.0f); |
408 | 77.9k | vint data_ai = float_to_int_rtn(clampzo(data_a) * 255.0f); |
409 | | |
410 | 77.9k | if (needs_swz) |
411 | 0 | { |
412 | 0 | vint swizzle_table[7]; |
413 | 0 | swizzle_table[ASTCENC_SWZ_0] = vint(0); |
414 | 0 | swizzle_table[ASTCENC_SWZ_1] = vint(255); |
415 | 0 | swizzle_table[ASTCENC_SWZ_R] = data_ri; |
416 | 0 | swizzle_table[ASTCENC_SWZ_G] = data_gi; |
417 | 0 | swizzle_table[ASTCENC_SWZ_B] = data_bi; |
418 | 0 | swizzle_table[ASTCENC_SWZ_A] = data_ai; |
419 | |
|
420 | 0 | if (needs_z) |
421 | 0 | { |
422 | 0 | vfloat data_x = (data_r * vfloat(2.0f)) - vfloat(1.0f); |
423 | 0 | vfloat data_y = (data_a * vfloat(2.0f)) - vfloat(1.0f); |
424 | 0 | vfloat data_z = vfloat(1.0f) - (data_x * data_x) - (data_y * data_y); |
425 | 0 | data_z = max(data_z, 0.0f); |
426 | 0 | data_z = (sqrt(data_z) * vfloat(0.5f)) + vfloat(0.5f); |
427 | |
|
428 | 0 | swizzle_table[ASTCENC_SWZ_Z] = float_to_int_rtn(min(data_z, 1.0f) * 255.0f); |
429 | 0 | } |
430 | |
|
431 | 0 | data_ri = swizzle_table[swz.r]; |
432 | 0 | data_gi = swizzle_table[swz.g]; |
433 | 0 | data_bi = swizzle_table[swz.b]; |
434 | 0 | data_ai = swizzle_table[swz.a]; |
435 | 0 | } |
436 | | |
437 | | // Errors are NaN encoded - convert to magenta error color |
438 | | // Branch is OK here - it is almost never true so predicts well |
439 | 77.9k | vmask nan_mask = data_r != data_r; |
440 | 77.9k | if (any(nan_mask)) |
441 | 20.8k | { |
442 | 20.8k | data_ri = select(data_ri, vint(0xFF), nan_mask); |
443 | 20.8k | data_gi = select(data_gi, vint(0x00), nan_mask); |
444 | 20.8k | data_bi = select(data_bi, vint(0xFF), nan_mask); |
445 | 20.8k | data_ai = select(data_ai, vint(0xFF), nan_mask); |
446 | 20.8k | } |
447 | | |
448 | 77.9k | vint data_rgbai = interleave_rgba8(data_ri, data_gi, data_bi, data_ai); |
449 | | // Static cast must be safe, as used_texels must be less than vector length |
450 | 77.9k | vmask store_mask = vint::lane_id() < vint(static_cast<int>(used_texels)); |
451 | 77.9k | store_lanes_masked(data8_row, data_rgbai, store_mask); |
452 | | |
453 | 77.9k | data8_row += ASTCENC_SIMD_WIDTH * 4; |
454 | 77.9k | idx += used_texels; |
455 | 77.9k | } |
456 | 29.2k | idx += nudge_x; |
457 | 29.2k | } |
458 | 3.84k | idx += nudge_y; |
459 | 3.84k | } |
460 | 3.84k | } |
461 | 0 | else if (img.data_type == ASTCENC_TYPE_F16) |
462 | 0 | { |
463 | 0 | for (size_t z = start_z; z < end_z; z++) |
464 | 0 | { |
465 | | // Fetch the image plane |
466 | 0 | uint16_t* data16 = static_cast<uint16_t*>(img.data[z]); |
467 | |
|
468 | 0 | for (size_t y = start_y; y < end_y; y++) |
469 | 0 | { |
470 | 0 | uint16_t* data16_row = data16 + (4 * size_x * y) + (4 * start_x); |
471 | |
|
472 | 0 | for (size_t x = 0; x < count_x; x++) |
473 | 0 | { |
474 | 0 | vint4 color; |
475 | | |
476 | | // NaNs are handled inline - no need to special case |
477 | 0 | if (needs_swz) |
478 | 0 | { |
479 | 0 | float data[7]; |
480 | 0 | data[ASTCENC_SWZ_0] = 0.0f; |
481 | 0 | data[ASTCENC_SWZ_1] = 1.0f; |
482 | 0 | data[ASTCENC_SWZ_R] = blk.data_r[idx]; |
483 | 0 | data[ASTCENC_SWZ_G] = blk.data_g[idx]; |
484 | 0 | data[ASTCENC_SWZ_B] = blk.data_b[idx]; |
485 | 0 | data[ASTCENC_SWZ_A] = blk.data_a[idx]; |
486 | |
|
487 | 0 | if (needs_z) |
488 | 0 | { |
489 | 0 | float xN = (data[0] * 2.0f) - 1.0f; |
490 | 0 | float yN = (data[3] * 2.0f) - 1.0f; |
491 | 0 | float zN = 1.0f - xN * xN - yN * yN; |
492 | 0 | if (zN < 0.0f) |
493 | 0 | { |
494 | 0 | zN = 0.0f; |
495 | 0 | } |
496 | 0 | data[ASTCENC_SWZ_Z] = (astc::sqrt(zN) * 0.5f) + 0.5f; |
497 | 0 | } |
498 | |
|
499 | 0 | vfloat4 colorf(data[swz.r], data[swz.g], data[swz.b], data[swz.a]); |
500 | 0 | color = float_to_float16(colorf); |
501 | 0 | } |
502 | 0 | else |
503 | 0 | { |
504 | 0 | vfloat4 colorf = blk.texel(idx); |
505 | 0 | color = float_to_float16(colorf); |
506 | 0 | } |
507 | | |
508 | | // TODO: Vectorize with store N shorts? |
509 | 0 | data16_row[0] = static_cast<uint16_t>(color.lane<0>()); |
510 | 0 | data16_row[1] = static_cast<uint16_t>(color.lane<1>()); |
511 | 0 | data16_row[2] = static_cast<uint16_t>(color.lane<2>()); |
512 | 0 | data16_row[3] = static_cast<uint16_t>(color.lane<3>()); |
513 | 0 | data16_row += 4; |
514 | 0 | idx++; |
515 | 0 | } |
516 | 0 | idx += nudge_x; |
517 | 0 | } |
518 | 0 | idx += nudge_y; |
519 | 0 | } |
520 | 0 | } |
521 | 0 | else // if (img.data_type == ASTCENC_TYPE_F32) |
522 | 0 | { |
523 | 0 | assert(img.data_type == ASTCENC_TYPE_F32); |
524 | | |
525 | 0 | for (size_t z = start_z; z < end_z; z++) |
526 | 0 | { |
527 | | // Fetch the image plane |
528 | 0 | float* data32 = static_cast<float*>(img.data[z]); |
529 | |
|
530 | 0 | for (size_t y = start_y; y < end_y; y++) |
531 | 0 | { |
532 | 0 | float* data32_row = data32 + (4 * size_x * y) + (4 * start_x); |
533 | |
|
534 | 0 | for (size_t x = 0; x < count_x; x++) |
535 | 0 | { |
536 | 0 | vfloat4 color = blk.texel(idx); |
537 | | |
538 | | // NaNs are handled inline - no need to special case |
539 | 0 | if (needs_swz) |
540 | 0 | { |
541 | 0 | float data[7]; |
542 | 0 | data[ASTCENC_SWZ_0] = 0.0f; |
543 | 0 | data[ASTCENC_SWZ_1] = 1.0f; |
544 | 0 | data[ASTCENC_SWZ_R] = color.lane<0>(); |
545 | 0 | data[ASTCENC_SWZ_G] = color.lane<1>(); |
546 | 0 | data[ASTCENC_SWZ_B] = color.lane<2>(); |
547 | 0 | data[ASTCENC_SWZ_A] = color.lane<3>(); |
548 | |
|
549 | 0 | if (needs_z) |
550 | 0 | { |
551 | 0 | float xN = (data[0] * 2.0f) - 1.0f; |
552 | 0 | float yN = (data[3] * 2.0f) - 1.0f; |
553 | 0 | float zN = 1.0f - xN * xN - yN * yN; |
554 | 0 | if (zN < 0.0f) |
555 | 0 | { |
556 | 0 | zN = 0.0f; |
557 | 0 | } |
558 | 0 | data[ASTCENC_SWZ_Z] = (astc::sqrt(zN) * 0.5f) + 0.5f; |
559 | 0 | } |
560 | |
|
561 | 0 | color = vfloat4(data[swz.r], data[swz.g], data[swz.b], data[swz.a]); |
562 | 0 | } |
563 | |
|
564 | 0 | store(color, data32_row); |
565 | 0 | data32_row += 4; |
566 | 0 | idx++; |
567 | 0 | } |
568 | 0 | idx += nudge_x; |
569 | 0 | } |
570 | 0 | idx += nudge_y; |
571 | 0 | } |
572 | 0 | } |
573 | 3.84k | } |