Skip to content

Commit 4703aab

Browse files
committed
Merge pull request #98919 from BlueCube3310/bcdec-fix-v4
bcdec: Fix decompressing mipmaps not divisible by 4
2 parents 63838c9 + ca7ad58 commit 4703aab

File tree

1 file changed

+87
-26
lines changed

1 file changed

+87
-26
lines changed

modules/bcdec/image_decompress_bcdec.cpp

Lines changed: 87 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ inline void bcdec_bc6h_half_u(const void *compressedBlock, void *decompressedBlo
4747
static void decompress_image(BCdecFormat format, const void *src, void *dst, const uint64_t width, const uint64_t height) {
4848
const uint8_t *src_blocks = reinterpret_cast<const uint8_t *>(src);
4949
uint8_t *dec_blocks = reinterpret_cast<uint8_t *>(dst);
50-
uint64_t src_pos = 0, dst_pos = 0;
5150

5251
#define DECOMPRESS_LOOP(func, block_size, color_bytesize, color_components) \
5352
for (uint64_t y = 0; y < height; y += 4) { \
@@ -59,34 +58,96 @@ static void decompress_image(BCdecFormat format, const void *src, void *dst, con
5958
dst_pos += 3 * width * color_bytesize; \
6059
}
6160

62-
switch (format) {
63-
case BCdec_BC1: {
64-
DECOMPRESS_LOOP(bcdec_bc1, BCDEC_BC1_BLOCK_SIZE, 4, 4)
65-
} break;
66-
case BCdec_BC2: {
67-
DECOMPRESS_LOOP(bcdec_bc2, BCDEC_BC2_BLOCK_SIZE, 4, 4)
68-
} break;
69-
case BCdec_BC3: {
70-
DECOMPRESS_LOOP(bcdec_bc3, BCDEC_BC3_BLOCK_SIZE, 4, 4)
71-
} break;
72-
case BCdec_BC4: {
73-
DECOMPRESS_LOOP(bcdec_bc4, BCDEC_BC4_BLOCK_SIZE, 1, 1)
74-
} break;
75-
case BCdec_BC5: {
76-
DECOMPRESS_LOOP(bcdec_bc5, BCDEC_BC5_BLOCK_SIZE, 2, 2)
77-
} break;
78-
case BCdec_BC6U: {
79-
DECOMPRESS_LOOP(bcdec_bc6h_half_u, BCDEC_BC6H_BLOCK_SIZE, 6, 3)
80-
} break;
81-
case BCdec_BC6S: {
82-
DECOMPRESS_LOOP(bcdec_bc6h_half_s, BCDEC_BC6H_BLOCK_SIZE, 6, 3)
83-
} break;
84-
case BCdec_BC7: {
85-
DECOMPRESS_LOOP(bcdec_bc7, BCDEC_BC7_BLOCK_SIZE, 4, 4)
86-
} break;
61+
#define DECOMPRESS_LOOP_SAFE(func, block_size, color_bytesize, color_components, output) \
62+
for (uint64_t y = 0; y < height; y += 4) { \
63+
for (uint64_t x = 0; x < width; x += 4) { \
64+
const uint32_t yblock = MIN(height - y, 4ul); \
65+
const uint32_t xblock = MIN(width - x, 4ul); \
66+
\
67+
const bool incomplete = yblock < 4 && xblock < 4; \
68+
uint8_t *dec_out = incomplete ? output : &dec_blocks[y * 4 * width + x * color_bytesize]; \
69+
\
70+
func(&src_blocks[src_pos], dec_out, 4 * color_components); \
71+
src_pos += block_size; \
72+
\
73+
if (incomplete) { \
74+
for (uint32_t cy = 0; cy < yblock; cy++) { \
75+
for (uint32_t cx = 0; cx < xblock; cx++) { \
76+
memcpy(&dec_blocks[(y + cy) * 4 * width + (x + cx) * color_bytesize], &output[cy * 4 + cx * color_bytesize], color_bytesize); \
77+
} \
78+
} \
79+
} \
80+
} \
81+
}
82+
83+
if (width % 4 != 0 || height % 4 != 0) {
84+
uint64_t src_pos = 0;
85+
86+
uint8_t r8_output[4 * 4];
87+
uint8_t rg8_output[4 * 4 * 2];
88+
uint8_t rgba8_output[4 * 4 * 4];
89+
uint8_t rgbh_output[4 * 4 * 6];
90+
91+
switch (format) {
92+
case BCdec_BC1: {
93+
DECOMPRESS_LOOP_SAFE(bcdec_bc1, BCDEC_BC1_BLOCK_SIZE, 4, 4, rgba8_output)
94+
} break;
95+
case BCdec_BC2: {
96+
DECOMPRESS_LOOP_SAFE(bcdec_bc2, BCDEC_BC2_BLOCK_SIZE, 4, 4, rgba8_output)
97+
} break;
98+
case BCdec_BC3: {
99+
DECOMPRESS_LOOP_SAFE(bcdec_bc3, BCDEC_BC3_BLOCK_SIZE, 4, 4, rgba8_output)
100+
} break;
101+
case BCdec_BC4: {
102+
DECOMPRESS_LOOP_SAFE(bcdec_bc4, BCDEC_BC4_BLOCK_SIZE, 1, 1, r8_output)
103+
} break;
104+
case BCdec_BC5: {
105+
DECOMPRESS_LOOP_SAFE(bcdec_bc5, BCDEC_BC5_BLOCK_SIZE, 2, 2, rg8_output)
106+
} break;
107+
case BCdec_BC6U: {
108+
DECOMPRESS_LOOP_SAFE(bcdec_bc6h_half_u, BCDEC_BC6H_BLOCK_SIZE, 6, 3, rgbh_output)
109+
} break;
110+
case BCdec_BC6S: {
111+
DECOMPRESS_LOOP_SAFE(bcdec_bc6h_half_s, BCDEC_BC6H_BLOCK_SIZE, 6, 3, rgbh_output)
112+
} break;
113+
case BCdec_BC7: {
114+
DECOMPRESS_LOOP_SAFE(bcdec_bc7, BCDEC_BC7_BLOCK_SIZE, 4, 4, rgba8_output)
115+
} break;
116+
}
117+
118+
} else {
119+
uint64_t src_pos = 0, dst_pos = 0;
120+
121+
switch (format) {
122+
case BCdec_BC1: {
123+
DECOMPRESS_LOOP(bcdec_bc1, BCDEC_BC1_BLOCK_SIZE, 4, 4)
124+
} break;
125+
case BCdec_BC2: {
126+
DECOMPRESS_LOOP(bcdec_bc2, BCDEC_BC2_BLOCK_SIZE, 4, 4)
127+
} break;
128+
case BCdec_BC3: {
129+
DECOMPRESS_LOOP(bcdec_bc3, BCDEC_BC3_BLOCK_SIZE, 4, 4)
130+
} break;
131+
case BCdec_BC4: {
132+
DECOMPRESS_LOOP(bcdec_bc4, BCDEC_BC4_BLOCK_SIZE, 1, 1)
133+
} break;
134+
case BCdec_BC5: {
135+
DECOMPRESS_LOOP(bcdec_bc5, BCDEC_BC5_BLOCK_SIZE, 2, 2)
136+
} break;
137+
case BCdec_BC6U: {
138+
DECOMPRESS_LOOP(bcdec_bc6h_half_u, BCDEC_BC6H_BLOCK_SIZE, 6, 3)
139+
} break;
140+
case BCdec_BC6S: {
141+
DECOMPRESS_LOOP(bcdec_bc6h_half_s, BCDEC_BC6H_BLOCK_SIZE, 6, 3)
142+
} break;
143+
case BCdec_BC7: {
144+
DECOMPRESS_LOOP(bcdec_bc7, BCDEC_BC7_BLOCK_SIZE, 4, 4)
145+
} break;
146+
}
87147
}
88148

89149
#undef DECOMPRESS_LOOP
150+
#undef DECOMPRESS_LOOP_SAFE
90151
}
91152

92153
void image_decompress_bcdec(Image *p_image) {

0 commit comments

Comments
 (0)