• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Tester Core
3  * ----------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Compressed Texture Utilities.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "tcuCompressedTexture.hpp"
25 #include "tcuTextureUtil.hpp"
26 #include "tcuAstcUtil.hpp"
27 
28 #include "deStringUtil.hpp"
29 #include "deFloat16.h"
30 
31 #include <algorithm>
32 
33 namespace tcu
34 {
35 
getBlockSize(CompressedTexFormat format)36 int getBlockSize (CompressedTexFormat format)
37 {
38 	if (isAstcFormat(format))
39 	{
40 		return astc::BLOCK_SIZE_BYTES;
41 	}
42 	else if (isEtcFormat(format))
43 	{
44 		switch (format)
45 		{
46 			case COMPRESSEDTEXFORMAT_ETC1_RGB8:							return 8;
47 			case COMPRESSEDTEXFORMAT_EAC_R11:							return 8;
48 			case COMPRESSEDTEXFORMAT_EAC_SIGNED_R11:					return 8;
49 			case COMPRESSEDTEXFORMAT_EAC_RG11:							return 16;
50 			case COMPRESSEDTEXFORMAT_EAC_SIGNED_RG11:					return 16;
51 			case COMPRESSEDTEXFORMAT_ETC2_RGB8:							return 8;
52 			case COMPRESSEDTEXFORMAT_ETC2_SRGB8:						return 8;
53 			case COMPRESSEDTEXFORMAT_ETC2_RGB8_PUNCHTHROUGH_ALPHA1:		return 8;
54 			case COMPRESSEDTEXFORMAT_ETC2_SRGB8_PUNCHTHROUGH_ALPHA1:	return 8;
55 			case COMPRESSEDTEXFORMAT_ETC2_EAC_RGBA8:					return 16;
56 			case COMPRESSEDTEXFORMAT_ETC2_EAC_SRGB8_ALPHA8:				return 16;
57 
58 			default:
59 				DE_ASSERT(false);
60 				return -1;
61 		}
62 	}
63 	else
64 	{
65 		DE_ASSERT(false);
66 		return -1;
67 	}
68 }
69 
getBlockPixelSize(CompressedTexFormat format)70 IVec3 getBlockPixelSize (CompressedTexFormat format)
71 {
72 	if (isEtcFormat(format))
73 	{
74 		return IVec3(4, 4, 1);
75 	}
76 	else if (isAstcFormat(format))
77 	{
78 		switch (format)
79 		{
80 			case COMPRESSEDTEXFORMAT_ASTC_4x4_RGBA:				return IVec3(4,  4,  1);
81 			case COMPRESSEDTEXFORMAT_ASTC_5x4_RGBA:				return IVec3(5,  4,  1);
82 			case COMPRESSEDTEXFORMAT_ASTC_5x5_RGBA:				return IVec3(5,  5,  1);
83 			case COMPRESSEDTEXFORMAT_ASTC_6x5_RGBA:				return IVec3(6,  5,  1);
84 			case COMPRESSEDTEXFORMAT_ASTC_6x6_RGBA:				return IVec3(6,  6,  1);
85 			case COMPRESSEDTEXFORMAT_ASTC_8x5_RGBA:				return IVec3(8,  5,  1);
86 			case COMPRESSEDTEXFORMAT_ASTC_8x6_RGBA:				return IVec3(8,  6,  1);
87 			case COMPRESSEDTEXFORMAT_ASTC_8x8_RGBA:				return IVec3(8,  8,  1);
88 			case COMPRESSEDTEXFORMAT_ASTC_10x5_RGBA:			return IVec3(10, 5,  1);
89 			case COMPRESSEDTEXFORMAT_ASTC_10x6_RGBA:			return IVec3(10, 6,  1);
90 			case COMPRESSEDTEXFORMAT_ASTC_10x8_RGBA:			return IVec3(10, 8,  1);
91 			case COMPRESSEDTEXFORMAT_ASTC_10x10_RGBA:			return IVec3(10, 10, 1);
92 			case COMPRESSEDTEXFORMAT_ASTC_12x10_RGBA:			return IVec3(12, 10, 1);
93 			case COMPRESSEDTEXFORMAT_ASTC_12x12_RGBA:			return IVec3(12, 12, 1);
94 			case COMPRESSEDTEXFORMAT_ASTC_4x4_SRGB8_ALPHA8:		return IVec3(4,  4,  1);
95 			case COMPRESSEDTEXFORMAT_ASTC_5x4_SRGB8_ALPHA8:		return IVec3(5,  4,  1);
96 			case COMPRESSEDTEXFORMAT_ASTC_5x5_SRGB8_ALPHA8:		return IVec3(5,  5,  1);
97 			case COMPRESSEDTEXFORMAT_ASTC_6x5_SRGB8_ALPHA8:		return IVec3(6,  5,  1);
98 			case COMPRESSEDTEXFORMAT_ASTC_6x6_SRGB8_ALPHA8:		return IVec3(6,  6,  1);
99 			case COMPRESSEDTEXFORMAT_ASTC_8x5_SRGB8_ALPHA8:		return IVec3(8,  5,  1);
100 			case COMPRESSEDTEXFORMAT_ASTC_8x6_SRGB8_ALPHA8:		return IVec3(8,  6,  1);
101 			case COMPRESSEDTEXFORMAT_ASTC_8x8_SRGB8_ALPHA8:		return IVec3(8,  8,  1);
102 			case COMPRESSEDTEXFORMAT_ASTC_10x5_SRGB8_ALPHA8:	return IVec3(10, 5,  1);
103 			case COMPRESSEDTEXFORMAT_ASTC_10x6_SRGB8_ALPHA8:	return IVec3(10, 6,  1);
104 			case COMPRESSEDTEXFORMAT_ASTC_10x8_SRGB8_ALPHA8:	return IVec3(10, 8,  1);
105 			case COMPRESSEDTEXFORMAT_ASTC_10x10_SRGB8_ALPHA8:	return IVec3(10, 10, 1);
106 			case COMPRESSEDTEXFORMAT_ASTC_12x10_SRGB8_ALPHA8:	return IVec3(12, 10, 1);
107 			case COMPRESSEDTEXFORMAT_ASTC_12x12_SRGB8_ALPHA8:	return IVec3(12, 12, 1);
108 
109 			default:
110 				DE_ASSERT(false);
111 				return IVec3();
112 		}
113 	}
114 	else
115 	{
116 		DE_ASSERT(false);
117 		return IVec3(-1);
118 	}
119 }
120 
isEtcFormat(CompressedTexFormat format)121 bool isEtcFormat (CompressedTexFormat format)
122 {
123 	switch (format)
124 	{
125 		case COMPRESSEDTEXFORMAT_ETC1_RGB8:
126 		case COMPRESSEDTEXFORMAT_EAC_R11:
127 		case COMPRESSEDTEXFORMAT_EAC_SIGNED_R11:
128 		case COMPRESSEDTEXFORMAT_EAC_RG11:
129 		case COMPRESSEDTEXFORMAT_EAC_SIGNED_RG11:
130 		case COMPRESSEDTEXFORMAT_ETC2_RGB8:
131 		case COMPRESSEDTEXFORMAT_ETC2_SRGB8:
132 		case COMPRESSEDTEXFORMAT_ETC2_RGB8_PUNCHTHROUGH_ALPHA1:
133 		case COMPRESSEDTEXFORMAT_ETC2_SRGB8_PUNCHTHROUGH_ALPHA1:
134 		case COMPRESSEDTEXFORMAT_ETC2_EAC_RGBA8:
135 		case COMPRESSEDTEXFORMAT_ETC2_EAC_SRGB8_ALPHA8:
136 			return true;
137 
138 		default:
139 			return false;
140 	}
141 }
142 
isAstcFormat(CompressedTexFormat format)143 bool isAstcFormat (CompressedTexFormat format)
144 {
145 	switch (format)
146 	{
147 		case COMPRESSEDTEXFORMAT_ASTC_4x4_RGBA:
148 		case COMPRESSEDTEXFORMAT_ASTC_5x4_RGBA:
149 		case COMPRESSEDTEXFORMAT_ASTC_5x5_RGBA:
150 		case COMPRESSEDTEXFORMAT_ASTC_6x5_RGBA:
151 		case COMPRESSEDTEXFORMAT_ASTC_6x6_RGBA:
152 		case COMPRESSEDTEXFORMAT_ASTC_8x5_RGBA:
153 		case COMPRESSEDTEXFORMAT_ASTC_8x6_RGBA:
154 		case COMPRESSEDTEXFORMAT_ASTC_8x8_RGBA:
155 		case COMPRESSEDTEXFORMAT_ASTC_10x5_RGBA:
156 		case COMPRESSEDTEXFORMAT_ASTC_10x6_RGBA:
157 		case COMPRESSEDTEXFORMAT_ASTC_10x8_RGBA:
158 		case COMPRESSEDTEXFORMAT_ASTC_10x10_RGBA:
159 		case COMPRESSEDTEXFORMAT_ASTC_12x10_RGBA:
160 		case COMPRESSEDTEXFORMAT_ASTC_12x12_RGBA:
161 		case COMPRESSEDTEXFORMAT_ASTC_4x4_SRGB8_ALPHA8:
162 		case COMPRESSEDTEXFORMAT_ASTC_5x4_SRGB8_ALPHA8:
163 		case COMPRESSEDTEXFORMAT_ASTC_5x5_SRGB8_ALPHA8:
164 		case COMPRESSEDTEXFORMAT_ASTC_6x5_SRGB8_ALPHA8:
165 		case COMPRESSEDTEXFORMAT_ASTC_6x6_SRGB8_ALPHA8:
166 		case COMPRESSEDTEXFORMAT_ASTC_8x5_SRGB8_ALPHA8:
167 		case COMPRESSEDTEXFORMAT_ASTC_8x6_SRGB8_ALPHA8:
168 		case COMPRESSEDTEXFORMAT_ASTC_8x8_SRGB8_ALPHA8:
169 		case COMPRESSEDTEXFORMAT_ASTC_10x5_SRGB8_ALPHA8:
170 		case COMPRESSEDTEXFORMAT_ASTC_10x6_SRGB8_ALPHA8:
171 		case COMPRESSEDTEXFORMAT_ASTC_10x8_SRGB8_ALPHA8:
172 		case COMPRESSEDTEXFORMAT_ASTC_10x10_SRGB8_ALPHA8:
173 		case COMPRESSEDTEXFORMAT_ASTC_12x10_SRGB8_ALPHA8:
174 		case COMPRESSEDTEXFORMAT_ASTC_12x12_SRGB8_ALPHA8:
175 			return true;
176 
177 		default:
178 			return false;
179 	}
180 }
181 
isAstcSRGBFormat(CompressedTexFormat format)182 bool isAstcSRGBFormat (CompressedTexFormat format)
183 {
184 	switch (format)
185 	{
186 		case COMPRESSEDTEXFORMAT_ASTC_4x4_SRGB8_ALPHA8:
187 		case COMPRESSEDTEXFORMAT_ASTC_5x4_SRGB8_ALPHA8:
188 		case COMPRESSEDTEXFORMAT_ASTC_5x5_SRGB8_ALPHA8:
189 		case COMPRESSEDTEXFORMAT_ASTC_6x5_SRGB8_ALPHA8:
190 		case COMPRESSEDTEXFORMAT_ASTC_6x6_SRGB8_ALPHA8:
191 		case COMPRESSEDTEXFORMAT_ASTC_8x5_SRGB8_ALPHA8:
192 		case COMPRESSEDTEXFORMAT_ASTC_8x6_SRGB8_ALPHA8:
193 		case COMPRESSEDTEXFORMAT_ASTC_8x8_SRGB8_ALPHA8:
194 		case COMPRESSEDTEXFORMAT_ASTC_10x5_SRGB8_ALPHA8:
195 		case COMPRESSEDTEXFORMAT_ASTC_10x6_SRGB8_ALPHA8:
196 		case COMPRESSEDTEXFORMAT_ASTC_10x8_SRGB8_ALPHA8:
197 		case COMPRESSEDTEXFORMAT_ASTC_10x10_SRGB8_ALPHA8:
198 		case COMPRESSEDTEXFORMAT_ASTC_12x10_SRGB8_ALPHA8:
199 		case COMPRESSEDTEXFORMAT_ASTC_12x12_SRGB8_ALPHA8:
200 			return true;
201 
202 		default:
203 			return false;
204 	}
205 }
206 
getUncompressedFormat(CompressedTexFormat format)207 TextureFormat getUncompressedFormat (CompressedTexFormat format)
208 {
209 	if (isEtcFormat(format))
210 	{
211 		switch (format)
212 		{
213 			case COMPRESSEDTEXFORMAT_ETC1_RGB8:							return TextureFormat(TextureFormat::RGB,	TextureFormat::UNORM_INT8);
214 			case COMPRESSEDTEXFORMAT_EAC_R11:							return TextureFormat(TextureFormat::R,		TextureFormat::UNORM_INT16);
215 			case COMPRESSEDTEXFORMAT_EAC_SIGNED_R11:					return TextureFormat(TextureFormat::R,		TextureFormat::SNORM_INT16);
216 			case COMPRESSEDTEXFORMAT_EAC_RG11:							return TextureFormat(TextureFormat::RG,		TextureFormat::UNORM_INT16);
217 			case COMPRESSEDTEXFORMAT_EAC_SIGNED_RG11:					return TextureFormat(TextureFormat::RG,		TextureFormat::SNORM_INT16);
218 			case COMPRESSEDTEXFORMAT_ETC2_RGB8:							return TextureFormat(TextureFormat::RGB,	TextureFormat::UNORM_INT8);
219 			case COMPRESSEDTEXFORMAT_ETC2_SRGB8:						return TextureFormat(TextureFormat::sRGB,	TextureFormat::UNORM_INT8);
220 			case COMPRESSEDTEXFORMAT_ETC2_RGB8_PUNCHTHROUGH_ALPHA1:		return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_INT8);
221 			case COMPRESSEDTEXFORMAT_ETC2_SRGB8_PUNCHTHROUGH_ALPHA1:	return TextureFormat(TextureFormat::sRGBA,	TextureFormat::UNORM_INT8);
222 			case COMPRESSEDTEXFORMAT_ETC2_EAC_RGBA8:					return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_INT8);
223 			case COMPRESSEDTEXFORMAT_ETC2_EAC_SRGB8_ALPHA8:				return TextureFormat(TextureFormat::sRGBA,	TextureFormat::UNORM_INT8);
224 
225 			default:
226 				DE_ASSERT(false);
227 				return TextureFormat();
228 		}
229 	}
230 	else if (isAstcFormat(format))
231 	{
232 		if (isAstcSRGBFormat(format))
233 			return TextureFormat(TextureFormat::sRGBA, TextureFormat::UNORM_INT8);
234 		else
235 			return TextureFormat(TextureFormat::RGBA, TextureFormat::HALF_FLOAT);
236 	}
237 	else
238 	{
239 		DE_ASSERT(false);
240 		return TextureFormat();
241 	}
242 }
243 
getAstcFormatByBlockSize(const IVec3 & size,bool isSRGB)244 CompressedTexFormat getAstcFormatByBlockSize (const IVec3& size, bool isSRGB)
245 {
246 	if (size.z() > 1)
247 		throw InternalError("3D ASTC textures not currently supported");
248 
249 	for (int fmtI = 0; fmtI < COMPRESSEDTEXFORMAT_LAST; fmtI++)
250 	{
251 		const CompressedTexFormat fmt = (CompressedTexFormat)fmtI;
252 
253 		if (isAstcFormat(fmt) && getBlockPixelSize(fmt) == size && isAstcSRGBFormat(fmt) == isSRGB)
254 			return fmt;
255 	}
256 
257 	throw InternalError("Invalid ASTC block size " + de::toString(size.x()) + "x" + de::toString(size.y()) + "x" + de::toString(size.z()));
258 }
259 
260 namespace
261 {
262 
263 // \todo [2013-08-06 nuutti] ETC and ASTC decompression codes are rather unrelated, and are already in their own "private" namespaces - should this be split to multiple files?
264 
265 namespace EtcDecompressInternal
266 {
267 
268 enum
269 {
270 	ETC2_BLOCK_WIDTH					= 4,
271 	ETC2_BLOCK_HEIGHT					= 4,
272 	ETC2_UNCOMPRESSED_PIXEL_SIZE_A8		= 1,
273 	ETC2_UNCOMPRESSED_PIXEL_SIZE_R11	= 2,
274 	ETC2_UNCOMPRESSED_PIXEL_SIZE_RG11	= 4,
275 	ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8	= 3,
276 	ETC2_UNCOMPRESSED_PIXEL_SIZE_RGBA8	= 4,
277 	ETC2_UNCOMPRESSED_BLOCK_SIZE_A8		= ETC2_BLOCK_WIDTH*ETC2_BLOCK_HEIGHT*ETC2_UNCOMPRESSED_PIXEL_SIZE_A8,
278 	ETC2_UNCOMPRESSED_BLOCK_SIZE_R11	= ETC2_BLOCK_WIDTH*ETC2_BLOCK_HEIGHT*ETC2_UNCOMPRESSED_PIXEL_SIZE_R11,
279 	ETC2_UNCOMPRESSED_BLOCK_SIZE_RG11	= ETC2_BLOCK_WIDTH*ETC2_BLOCK_HEIGHT*ETC2_UNCOMPRESSED_PIXEL_SIZE_RG11,
280 	ETC2_UNCOMPRESSED_BLOCK_SIZE_RGB8	= ETC2_BLOCK_WIDTH*ETC2_BLOCK_HEIGHT*ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8,
281 	ETC2_UNCOMPRESSED_BLOCK_SIZE_RGBA8	= ETC2_BLOCK_WIDTH*ETC2_BLOCK_HEIGHT*ETC2_UNCOMPRESSED_PIXEL_SIZE_RGBA8
282 };
283 
get64BitBlock(const deUint8 * src,int blockNdx)284 inline deUint64 get64BitBlock (const deUint8* src, int blockNdx)
285 {
286 	// Stored in big-endian form.
287 	deUint64 block = 0;
288 
289 	for (int i = 0; i < 8; i++)
290 		block = (block << 8ull) | (deUint64)(src[blockNdx*8+i]);
291 
292 	return block;
293 }
294 
295 // Return the first 64 bits of a 128 bit block.
get128BitBlockStart(const deUint8 * src,int blockNdx)296 inline deUint64 get128BitBlockStart (const deUint8* src, int blockNdx)
297 {
298 	return get64BitBlock(src, 2*blockNdx);
299 }
300 
301 // Return the last 64 bits of a 128 bit block.
get128BitBlockEnd(const deUint8 * src,int blockNdx)302 inline deUint64 get128BitBlockEnd (const deUint8* src, int blockNdx)
303 {
304 	return get64BitBlock(src, 2*blockNdx + 1);
305 }
306 
getBit(deUint64 src,int bit)307 inline deUint32 getBit (deUint64 src, int bit)
308 {
309 	return (src >> bit) & 1;
310 }
311 
getBits(deUint64 src,int low,int high)312 inline deUint32 getBits (deUint64 src, int low, int high)
313 {
314 	const int numBits = (high-low) + 1;
315 	DE_ASSERT(de::inRange(numBits, 1, 32));
316 	if (numBits < 32)
317 		return (deUint32)((src >> low) & ((1u<<numBits)-1));
318 	else
319 		return (deUint32)((src >> low) & 0xFFFFFFFFu);
320 }
321 
extend4To8(deUint8 src)322 inline deUint8 extend4To8 (deUint8 src)
323 {
324 	DE_ASSERT((src & ~((1<<4)-1)) == 0);
325 	return (deUint8)((src << 4) | src);
326 }
327 
extend5To8(deUint8 src)328 inline deUint8 extend5To8 (deUint8 src)
329 {
330 	DE_ASSERT((src & ~((1<<5)-1)) == 0);
331 	return (deUint8)((src << 3) | (src >> 2));
332 }
333 
extend6To8(deUint8 src)334 inline deUint8 extend6To8 (deUint8 src)
335 {
336 	DE_ASSERT((src & ~((1<<6)-1)) == 0);
337 	return (deUint8)((src << 2) | (src >> 4));
338 }
339 
extend7To8(deUint8 src)340 inline deUint8 extend7To8 (deUint8 src)
341 {
342 	DE_ASSERT((src & ~((1<<7)-1)) == 0);
343 	return (deUint8)((src << 1) | (src >> 6));
344 }
345 
extendSigned3To8(deUint8 src)346 inline deInt8 extendSigned3To8 (deUint8 src)
347 {
348 	const bool isNeg = (src & (1<<2)) != 0;
349 	return (deInt8)((isNeg ? ~((1<<3)-1) : 0) | src);
350 }
351 
extend5Delta3To8(deUint8 base5,deUint8 delta3)352 inline deUint8 extend5Delta3To8 (deUint8 base5, deUint8 delta3)
353 {
354 	const deUint8 t = (deUint8)((deInt8)base5 + extendSigned3To8(delta3));
355 	return extend5To8(t);
356 }
357 
extend11To16(deUint16 src)358 inline deUint16 extend11To16 (deUint16 src)
359 {
360 	DE_ASSERT((src & ~((1<<11)-1)) == 0);
361 	return (deUint16)((src << 5) | (src >> 6));
362 }
363 
extend11To16WithSign(deInt16 src)364 inline deInt16 extend11To16WithSign (deInt16 src)
365 {
366 	if (src < 0)
367 		return (deInt16)(-(deInt16)extend11To16((deUint16)(-src)));
368 	else
369 		return (deInt16)extend11To16(src);
370 }
371 
decompressETC1Block(deUint8 dst[ETC2_UNCOMPRESSED_BLOCK_SIZE_RGB8],deUint64 src)372 void decompressETC1Block (deUint8 dst[ETC2_UNCOMPRESSED_BLOCK_SIZE_RGB8], deUint64 src)
373 {
374 	const int		diffBit		= (int)getBit(src, 33);
375 	const int		flipBit		= (int)getBit(src, 32);
376 	const deUint32	table[2]	= { getBits(src, 37, 39), getBits(src, 34, 36) };
377 	deUint8			baseR[2];
378 	deUint8			baseG[2];
379 	deUint8			baseB[2];
380 
381 	if (diffBit == 0)
382 	{
383 		// Individual mode.
384 		baseR[0] = extend4To8((deUint8)getBits(src, 60, 63));
385 		baseR[1] = extend4To8((deUint8)getBits(src, 56, 59));
386 		baseG[0] = extend4To8((deUint8)getBits(src, 52, 55));
387 		baseG[1] = extend4To8((deUint8)getBits(src, 48, 51));
388 		baseB[0] = extend4To8((deUint8)getBits(src, 44, 47));
389 		baseB[1] = extend4To8((deUint8)getBits(src, 40, 43));
390 	}
391 	else
392 	{
393 		// Differential mode (diffBit == 1).
394 		deUint8 bR = (deUint8)getBits(src, 59, 63); // 5b
395 		deUint8 dR = (deUint8)getBits(src, 56, 58); // 3b
396 		deUint8 bG = (deUint8)getBits(src, 51, 55);
397 		deUint8 dG = (deUint8)getBits(src, 48, 50);
398 		deUint8 bB = (deUint8)getBits(src, 43, 47);
399 		deUint8 dB = (deUint8)getBits(src, 40, 42);
400 
401 		baseR[0] = extend5To8(bR);
402 		baseG[0] = extend5To8(bG);
403 		baseB[0] = extend5To8(bB);
404 
405 		baseR[1] = extend5Delta3To8(bR, dR);
406 		baseG[1] = extend5Delta3To8(bG, dG);
407 		baseB[1] = extend5Delta3To8(bB, dB);
408 	}
409 
410 	static const int modifierTable[8][4] =
411 	{
412 	//	  00   01   10    11
413 		{  2,   8,  -2,   -8 },
414 		{  5,  17,  -5,  -17 },
415 		{  9,  29,  -9,  -29 },
416 		{ 13,  42, -13,  -42 },
417 		{ 18,  60, -18,  -60 },
418 		{ 24,  80, -24,  -80 },
419 		{ 33, 106, -33, -106 },
420 		{ 47, 183, -47, -183 }
421 	};
422 
423 	// Write final pixels.
424 	for (int pixelNdx = 0; pixelNdx < ETC2_BLOCK_HEIGHT*ETC2_BLOCK_WIDTH; pixelNdx++)
425 	{
426 		const int		x				= pixelNdx / ETC2_BLOCK_HEIGHT;
427 		const int		y				= pixelNdx % ETC2_BLOCK_HEIGHT;
428 		const int		dstOffset		= (y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8;
429 		const int		subBlock		= ((flipBit ? y : x) >= 2) ? 1 : 0;
430 		const deUint32	tableNdx		= table[subBlock];
431 		const deUint32	modifierNdx		= (getBit(src, 16+pixelNdx) << 1) | getBit(src, pixelNdx);
432 		const int		modifier		= modifierTable[tableNdx][modifierNdx];
433 
434 		dst[dstOffset+0] = (deUint8)deClamp32((int)baseR[subBlock] + modifier, 0, 255);
435 		dst[dstOffset+1] = (deUint8)deClamp32((int)baseG[subBlock] + modifier, 0, 255);
436 		dst[dstOffset+2] = (deUint8)deClamp32((int)baseB[subBlock] + modifier, 0, 255);
437 	}
438 }
439 
440 // if alphaMode is true, do PUNCHTHROUGH and store alpha to alphaDst; otherwise do ordinary ETC2 RGB8.
decompressETC2Block(deUint8 dst[ETC2_UNCOMPRESSED_BLOCK_SIZE_RGB8],deUint64 src,deUint8 alphaDst[ETC2_UNCOMPRESSED_BLOCK_SIZE_A8],bool alphaMode)441 void decompressETC2Block (deUint8 dst[ETC2_UNCOMPRESSED_BLOCK_SIZE_RGB8], deUint64 src, deUint8 alphaDst[ETC2_UNCOMPRESSED_BLOCK_SIZE_A8], bool alphaMode)
442 {
443 	enum Etc2Mode
444 	{
445 		MODE_INDIVIDUAL = 0,
446 		MODE_DIFFERENTIAL,
447 		MODE_T,
448 		MODE_H,
449 		MODE_PLANAR,
450 
451 		MODE_LAST
452 	};
453 
454 	const int		diffOpaqueBit	= (int)getBit(src, 33);
455 	const deInt8	selBR			= (deInt8)getBits(src, 59, 63);	// 5 bits.
456 	const deInt8	selBG			= (deInt8)getBits(src, 51, 55);
457 	const deInt8	selBB			= (deInt8)getBits(src, 43, 47);
458 	const deInt8	selDR			= extendSigned3To8((deUint8)getBits(src, 56, 58)); // 3 bits.
459 	const deInt8	selDG			= extendSigned3To8((deUint8)getBits(src, 48, 50));
460 	const deInt8	selDB			= extendSigned3To8((deUint8)getBits(src, 40, 42));
461 	Etc2Mode		mode;
462 
463 	if (!alphaMode && diffOpaqueBit == 0)
464 		mode = MODE_INDIVIDUAL;
465 	else if (!de::inRange(selBR + selDR, 0, 31))
466 		mode = MODE_T;
467 	else if (!de::inRange(selBG + selDG, 0, 31))
468 		mode = MODE_H;
469 	else if (!de::inRange(selBB + selDB, 0, 31))
470 		mode = MODE_PLANAR;
471 	else
472 		mode = MODE_DIFFERENTIAL;
473 
474 	if (mode == MODE_INDIVIDUAL || mode == MODE_DIFFERENTIAL)
475 	{
476 		// Individual and differential modes have some steps in common, handle them here.
477 		static const int modifierTable[8][4] =
478 		{
479 		//	  00   01   10    11
480 			{  2,   8,  -2,   -8 },
481 			{  5,  17,  -5,  -17 },
482 			{  9,  29,  -9,  -29 },
483 			{ 13,  42, -13,  -42 },
484 			{ 18,  60, -18,  -60 },
485 			{ 24,  80, -24,  -80 },
486 			{ 33, 106, -33, -106 },
487 			{ 47, 183, -47, -183 }
488 		};
489 
490 		const int		flipBit		= (int)getBit(src, 32);
491 		const deUint32	table[2]	= { getBits(src, 37, 39), getBits(src, 34, 36) };
492 		deUint8			baseR[2];
493 		deUint8			baseG[2];
494 		deUint8			baseB[2];
495 
496 		if (mode == MODE_INDIVIDUAL)
497 		{
498 			// Individual mode, initial values.
499 			baseR[0] = extend4To8((deUint8)getBits(src, 60, 63));
500 			baseR[1] = extend4To8((deUint8)getBits(src, 56, 59));
501 			baseG[0] = extend4To8((deUint8)getBits(src, 52, 55));
502 			baseG[1] = extend4To8((deUint8)getBits(src, 48, 51));
503 			baseB[0] = extend4To8((deUint8)getBits(src, 44, 47));
504 			baseB[1] = extend4To8((deUint8)getBits(src, 40, 43));
505 		}
506 		else
507 		{
508 			// Differential mode, initial values.
509 			baseR[0] = extend5To8(selBR);
510 			baseG[0] = extend5To8(selBG);
511 			baseB[0] = extend5To8(selBB);
512 
513 			baseR[1] = extend5To8((deUint8)(selBR + selDR));
514 			baseG[1] = extend5To8((deUint8)(selBG + selDG));
515 			baseB[1] = extend5To8((deUint8)(selBB + selDB));
516 		}
517 
518 		// Write final pixels for individual or differential mode.
519 		for (int pixelNdx = 0; pixelNdx < ETC2_BLOCK_HEIGHT*ETC2_BLOCK_WIDTH; pixelNdx++)
520 		{
521 			const int		x				= pixelNdx / ETC2_BLOCK_HEIGHT;
522 			const int		y				= pixelNdx % ETC2_BLOCK_HEIGHT;
523 			const int		dstOffset		= (y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8;
524 			const int		subBlock		= ((flipBit ? y : x) >= 2) ? 1 : 0;
525 			const deUint32	tableNdx		= table[subBlock];
526 			const deUint32	modifierNdx		= (getBit(src, 16+pixelNdx) << 1) | getBit(src, pixelNdx);
527 			const int		alphaDstOffset	= (y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_A8; // Only needed for PUNCHTHROUGH version.
528 
529 			// If doing PUNCHTHROUGH version (alphaMode), opaque bit may affect colors.
530 			if (alphaMode && diffOpaqueBit == 0 && modifierNdx == 2)
531 			{
532 				dst[dstOffset+0]			= 0;
533 				dst[dstOffset+1]			= 0;
534 				dst[dstOffset+2]			= 0;
535 				alphaDst[alphaDstOffset]	= 0;
536 			}
537 			else
538 			{
539 				int modifier;
540 
541 				// PUNCHTHROUGH version and opaque bit may also affect modifiers.
542 				if (alphaMode && diffOpaqueBit == 0 && (modifierNdx == 0 || modifierNdx == 2))
543 					modifier = 0;
544 				else
545 					modifier = modifierTable[tableNdx][modifierNdx];
546 
547 				dst[dstOffset+0] = (deUint8)deClamp32((int)baseR[subBlock] + modifier, 0, 255);
548 				dst[dstOffset+1] = (deUint8)deClamp32((int)baseG[subBlock] + modifier, 0, 255);
549 				dst[dstOffset+2] = (deUint8)deClamp32((int)baseB[subBlock] + modifier, 0, 255);
550 
551 				if (alphaMode)
552 					alphaDst[alphaDstOffset] = 255;
553 			}
554 		}
555 	}
556 	else if (mode == MODE_T || mode == MODE_H)
557 	{
558 		// T and H modes have some steps in common, handle them here.
559 		static const int distTable[8] = { 3, 6, 11, 16, 23, 32, 41, 64 };
560 
561 		deUint8 paintR[4];
562 		deUint8 paintG[4];
563 		deUint8 paintB[4];
564 
565 		if (mode == MODE_T)
566 		{
567 			// T mode, calculate paint values.
568 			const deUint8	R1a			= (deUint8)getBits(src, 59, 60);
569 			const deUint8	R1b			= (deUint8)getBits(src, 56, 57);
570 			const deUint8	G1			= (deUint8)getBits(src, 52, 55);
571 			const deUint8	B1			= (deUint8)getBits(src, 48, 51);
572 			const deUint8	R2			= (deUint8)getBits(src, 44, 47);
573 			const deUint8	G2			= (deUint8)getBits(src, 40, 43);
574 			const deUint8	B2			= (deUint8)getBits(src, 36, 39);
575 			const deUint32	distNdx		= (getBits(src, 34, 35) << 1) | getBit(src, 32);
576 			const int		dist		= distTable[distNdx];
577 
578 			paintR[0] = extend4To8((deUint8)((R1a << 2) | R1b));
579 			paintG[0] = extend4To8(G1);
580 			paintB[0] = extend4To8(B1);
581 			paintR[2] = extend4To8(R2);
582 			paintG[2] = extend4To8(G2);
583 			paintB[2] = extend4To8(B2);
584 			paintR[1] = (deUint8)deClamp32((int)paintR[2] + dist, 0, 255);
585 			paintG[1] = (deUint8)deClamp32((int)paintG[2] + dist, 0, 255);
586 			paintB[1] = (deUint8)deClamp32((int)paintB[2] + dist, 0, 255);
587 			paintR[3] = (deUint8)deClamp32((int)paintR[2] - dist, 0, 255);
588 			paintG[3] = (deUint8)deClamp32((int)paintG[2] - dist, 0, 255);
589 			paintB[3] = (deUint8)deClamp32((int)paintB[2] - dist, 0, 255);
590 		}
591 		else
592 		{
593 			// H mode, calculate paint values.
594 			const deUint8	R1		= (deUint8)getBits(src, 59, 62);
595 			const deUint8	G1a		= (deUint8)getBits(src, 56, 58);
596 			const deUint8	G1b		= (deUint8)getBit(src, 52);
597 			const deUint8	B1a		= (deUint8)getBit(src, 51);
598 			const deUint8	B1b		= (deUint8)getBits(src, 47, 49);
599 			const deUint8	R2		= (deUint8)getBits(src, 43, 46);
600 			const deUint8	G2		= (deUint8)getBits(src, 39, 42);
601 			const deUint8	B2		= (deUint8)getBits(src, 35, 38);
602 			deUint8			baseR[2];
603 			deUint8			baseG[2];
604 			deUint8			baseB[2];
605 			deUint32		baseValue[2];
606 			deUint32		distNdx;
607 			int				dist;
608 
609 			baseR[0]		= extend4To8(R1);
610 			baseG[0]		= extend4To8((deUint8)((G1a << 1) | G1b));
611 			baseB[0]		= extend4To8((deUint8)((B1a << 3) | B1b));
612 			baseR[1]		= extend4To8(R2);
613 			baseG[1]		= extend4To8(G2);
614 			baseB[1]		= extend4To8(B2);
615 			baseValue[0]	= (((deUint32)baseR[0]) << 16) | (((deUint32)baseG[0]) << 8) | baseB[0];
616 			baseValue[1]	= (((deUint32)baseR[1]) << 16) | (((deUint32)baseG[1]) << 8) | baseB[1];
617 			distNdx			= (getBit(src, 34) << 2) | (getBit(src, 32) << 1) | (deUint32)(baseValue[0] >= baseValue[1]);
618 			dist			= distTable[distNdx];
619 
620 			paintR[0]		= (deUint8)deClamp32((int)baseR[0] + dist, 0, 255);
621 			paintG[0]		= (deUint8)deClamp32((int)baseG[0] + dist, 0, 255);
622 			paintB[0]		= (deUint8)deClamp32((int)baseB[0] + dist, 0, 255);
623 			paintR[1]		= (deUint8)deClamp32((int)baseR[0] - dist, 0, 255);
624 			paintG[1]		= (deUint8)deClamp32((int)baseG[0] - dist, 0, 255);
625 			paintB[1]		= (deUint8)deClamp32((int)baseB[0] - dist, 0, 255);
626 			paintR[2]		= (deUint8)deClamp32((int)baseR[1] + dist, 0, 255);
627 			paintG[2]		= (deUint8)deClamp32((int)baseG[1] + dist, 0, 255);
628 			paintB[2]		= (deUint8)deClamp32((int)baseB[1] + dist, 0, 255);
629 			paintR[3]		= (deUint8)deClamp32((int)baseR[1] - dist, 0, 255);
630 			paintG[3]		= (deUint8)deClamp32((int)baseG[1] - dist, 0, 255);
631 			paintB[3]		= (deUint8)deClamp32((int)baseB[1] - dist, 0, 255);
632 		}
633 
634 		// Write final pixels for T or H mode.
635 		for (int pixelNdx = 0; pixelNdx < ETC2_BLOCK_HEIGHT*ETC2_BLOCK_WIDTH; pixelNdx++)
636 		{
637 			const int		x				= pixelNdx / ETC2_BLOCK_HEIGHT;
638 			const int		y				= pixelNdx % ETC2_BLOCK_HEIGHT;
639 			const int		dstOffset		= (y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8;
640 			const deUint32	paintNdx		= (getBit(src, 16+pixelNdx) << 1) | getBit(src, pixelNdx);
641 			const int		alphaDstOffset	= (y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_A8; // Only needed for PUNCHTHROUGH version.
642 
643 			if (alphaMode && diffOpaqueBit == 0 && paintNdx == 2)
644 			{
645 				dst[dstOffset+0]			= 0;
646 				dst[dstOffset+1]			= 0;
647 				dst[dstOffset+2]			= 0;
648 				alphaDst[alphaDstOffset]	= 0;
649 			}
650 			else
651 			{
652 				dst[dstOffset+0] = (deUint8)deClamp32((int)paintR[paintNdx], 0, 255);
653 				dst[dstOffset+1] = (deUint8)deClamp32((int)paintG[paintNdx], 0, 255);
654 				dst[dstOffset+2] = (deUint8)deClamp32((int)paintB[paintNdx], 0, 255);
655 
656 				if (alphaMode)
657 					alphaDst[alphaDstOffset] = 255;
658 			}
659 		}
660 	}
661 	else
662 	{
663 		// Planar mode.
664 		const deUint8 GO1	= (deUint8)getBit(src, 56);
665 		const deUint8 GO2	= (deUint8)getBits(src, 49, 54);
666 		const deUint8 BO1	= (deUint8)getBit(src, 48);
667 		const deUint8 BO2	= (deUint8)getBits(src, 43, 44);
668 		const deUint8 BO3	= (deUint8)getBits(src, 39, 41);
669 		const deUint8 RH1	= (deUint8)getBits(src, 34, 38);
670 		const deUint8 RH2	= (deUint8)getBit(src, 32);
671 		const deUint8 RO	= extend6To8((deUint8)getBits(src, 57, 62));
672 		const deUint8 GO	= extend7To8((deUint8)((GO1 << 6) | GO2));
673 		const deUint8 BO	= extend6To8((deUint8)((BO1 << 5) | (BO2 << 3) | BO3));
674 		const deUint8 RH	= extend6To8((deUint8)((RH1 << 1) | RH2));
675 		const deUint8 GH	= extend7To8((deUint8)getBits(src, 25, 31));
676 		const deUint8 BH	= extend6To8((deUint8)getBits(src, 19, 24));
677 		const deUint8 RV	= extend6To8((deUint8)getBits(src, 13, 18));
678 		const deUint8 GV	= extend7To8((deUint8)getBits(src, 6, 12));
679 		const deUint8 BV	= extend6To8((deUint8)getBits(src, 0, 5));
680 
681 		// Write final pixels for planar mode.
682 		for (int y = 0; y < 4; y++)
683 		{
684 			for (int x = 0; x < 4; x++)
685 			{
686 				const int dstOffset			= (y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8;
687 				const int unclampedR		= (x * ((int)RH-(int)RO) + y * ((int)RV-(int)RO) + 4*(int)RO + 2) >> 2;
688 				const int unclampedG		= (x * ((int)GH-(int)GO) + y * ((int)GV-(int)GO) + 4*(int)GO + 2) >> 2;
689 				const int unclampedB		= (x * ((int)BH-(int)BO) + y * ((int)BV-(int)BO) + 4*(int)BO + 2) >> 2;
690 				const int alphaDstOffset	= (y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_A8; // Only needed for PUNCHTHROUGH version.
691 
692 				dst[dstOffset+0] = (deUint8)deClamp32(unclampedR, 0, 255);
693 				dst[dstOffset+1] = (deUint8)deClamp32(unclampedG, 0, 255);
694 				dst[dstOffset+2] = (deUint8)deClamp32(unclampedB, 0, 255);
695 
696 				if (alphaMode)
697 					alphaDst[alphaDstOffset] = 255;
698 			}
699 		}
700 	}
701 }
702 
decompressEAC8Block(deUint8 dst[ETC2_UNCOMPRESSED_BLOCK_SIZE_A8],deUint64 src)703 void decompressEAC8Block (deUint8 dst[ETC2_UNCOMPRESSED_BLOCK_SIZE_A8], deUint64 src)
704 {
705 	static const int modifierTable[16][8] =
706 	{
707 		{-3,  -6,  -9, -15,  2,  5,  8, 14},
708 		{-3,  -7, -10, -13,  2,  6,  9, 12},
709 		{-2,  -5,  -8, -13,  1,  4,  7, 12},
710 		{-2,  -4,  -6, -13,  1,  3,  5, 12},
711 		{-3,  -6,  -8, -12,  2,  5,  7, 11},
712 		{-3,  -7,  -9, -11,  2,  6,  8, 10},
713 		{-4,  -7,  -8, -11,  3,  6,  7, 10},
714 		{-3,  -5,  -8, -11,  2,  4,  7, 10},
715 		{-2,  -6,  -8, -10,  1,  5,  7,  9},
716 		{-2,  -5,  -8, -10,  1,  4,  7,  9},
717 		{-2,  -4,  -8, -10,  1,  3,  7,  9},
718 		{-2,  -5,  -7, -10,  1,  4,  6,  9},
719 		{-3,  -4,  -7, -10,  2,  3,  6,  9},
720 		{-1,  -2,  -3, -10,  0,  1,  2,  9},
721 		{-4,  -6,  -8,  -9,  3,  5,  7,  8},
722 		{-3,  -5,  -7,  -9,  2,  4,  6,  8}
723 	};
724 
725 	const deUint8	baseCodeword	= (deUint8)getBits(src, 56, 63);
726 	const deUint8	multiplier		= (deUint8)getBits(src, 52, 55);
727 	const deUint32	tableNdx		= getBits(src, 48, 51);
728 
729 	for (int pixelNdx = 0; pixelNdx < ETC2_BLOCK_HEIGHT*ETC2_BLOCK_WIDTH; pixelNdx++)
730 	{
731 		const int		x				= pixelNdx / ETC2_BLOCK_HEIGHT;
732 		const int		y				= pixelNdx % ETC2_BLOCK_HEIGHT;
733 		const int		dstOffset		= (y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_A8;
734 		const int		pixelBitNdx		= 45 - 3*pixelNdx;
735 		const deUint32	modifierNdx		= (getBit(src, pixelBitNdx + 2) << 2) | (getBit(src, pixelBitNdx + 1) << 1) | getBit(src, pixelBitNdx);
736 		const int		modifier		= modifierTable[tableNdx][modifierNdx];
737 
738 		dst[dstOffset] = (deUint8)deClamp32((int)baseCodeword + (int)multiplier*modifier, 0, 255);
739 	}
740 }
741 
decompressEAC11Block(deUint8 dst[ETC2_UNCOMPRESSED_BLOCK_SIZE_R11],deUint64 src,bool signedMode)742 void decompressEAC11Block (deUint8 dst[ETC2_UNCOMPRESSED_BLOCK_SIZE_R11], deUint64 src, bool signedMode)
743 {
744 	static const int modifierTable[16][8] =
745 	{
746 		{-3,  -6,  -9, -15,  2,  5,  8, 14},
747 		{-3,  -7, -10, -13,  2,  6,  9, 12},
748 		{-2,  -5,  -8, -13,  1,  4,  7, 12},
749 		{-2,  -4,  -6, -13,  1,  3,  5, 12},
750 		{-3,  -6,  -8, -12,  2,  5,  7, 11},
751 		{-3,  -7,  -9, -11,  2,  6,  8, 10},
752 		{-4,  -7,  -8, -11,  3,  6,  7, 10},
753 		{-3,  -5,  -8, -11,  2,  4,  7, 10},
754 		{-2,  -6,  -8, -10,  1,  5,  7,  9},
755 		{-2,  -5,  -8, -10,  1,  4,  7,  9},
756 		{-2,  -4,  -8, -10,  1,  3,  7,  9},
757 		{-2,  -5,  -7, -10,  1,  4,  6,  9},
758 		{-3,  -4,  -7, -10,  2,  3,  6,  9},
759 		{-1,  -2,  -3, -10,  0,  1,  2,  9},
760 		{-4,  -6,  -8,  -9,  3,  5,  7,  8},
761 		{-3,  -5,  -7,  -9,  2,  4,  6,  8}
762 	};
763 
764 	const deInt32 multiplier	= (deInt32)getBits(src, 52, 55);
765 	const deInt32 tableNdx		= (deInt32)getBits(src, 48, 51);
766 	deInt32 baseCodeword		= (deInt32)getBits(src, 56, 63);
767 
768 	if (signedMode)
769 	{
770 		if (baseCodeword > 127)
771 			baseCodeword -= 256;
772 		if (baseCodeword == -128)
773 			baseCodeword = -127;
774 	}
775 
776 	for (int pixelNdx = 0; pixelNdx < ETC2_BLOCK_HEIGHT*ETC2_BLOCK_WIDTH; pixelNdx++)
777 	{
778 		const int		x				= pixelNdx / ETC2_BLOCK_HEIGHT;
779 		const int		y				= pixelNdx % ETC2_BLOCK_HEIGHT;
780 		const int		dstOffset		= (y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_R11;
781 		const int		pixelBitNdx		= 45 - 3*pixelNdx;
782 		const deUint32	modifierNdx		= (getBit(src, pixelBitNdx + 2) << 2) | (getBit(src, pixelBitNdx + 1) << 1) | getBit(src, pixelBitNdx);
783 		const int		modifier		= modifierTable[tableNdx][modifierNdx];
784 
785 		if (signedMode)
786 		{
787 			deInt16 value;
788 
789 			if (multiplier != 0)
790 				value = (deInt16)deClamp32(baseCodeword*8 + multiplier*modifier*8, -1023, 1023);
791 			else
792 				value = (deInt16)deClamp32(baseCodeword*8 + modifier, -1023, 1023);
793 
794 			*((deInt16*)(dst + dstOffset)) = value;
795 		}
796 		else
797 		{
798 			deUint16 value;
799 
800 			if (multiplier != 0)
801 				value = (deUint16)deClamp32(baseCodeword*8 + 4 + multiplier*modifier*8, 0, 2047);
802 			else
803 				value= (deUint16)deClamp32(baseCodeword*8 + 4 + modifier, 0, 2047);
804 
805 			*((deUint16*)(dst + dstOffset)) = value;
806 		}
807 	}
808 }
809 
810 } // EtcDecompressInternal
811 
decompressETC1(const PixelBufferAccess & dst,const deUint8 * src)812 void decompressETC1 (const PixelBufferAccess& dst, const deUint8* src)
813 {
814 	using namespace EtcDecompressInternal;
815 
816 	deUint8* const	dstPtr			= (deUint8*)dst.getDataPtr();
817 	const deUint64	compressedBlock = get64BitBlock(src, 0);
818 
819 	decompressETC1Block(dstPtr, compressedBlock);
820 }
821 
decompressETC2(const PixelBufferAccess & dst,const deUint8 * src)822 void decompressETC2 (const PixelBufferAccess& dst, const deUint8* src)
823 {
824 	using namespace EtcDecompressInternal;
825 
826 	deUint8* const	dstPtr			= (deUint8*)dst.getDataPtr();
827 	const deUint64	compressedBlock = get64BitBlock(src, 0);
828 
829 	decompressETC2Block(dstPtr, compressedBlock, NULL, false);
830 }
831 
decompressETC2_EAC_RGBA8(const PixelBufferAccess & dst,const deUint8 * src)832 void decompressETC2_EAC_RGBA8 (const PixelBufferAccess& dst, const deUint8* src)
833 {
834 	using namespace EtcDecompressInternal;
835 
836 	deUint8* const	dstPtr			= (deUint8*)dst.getDataPtr();
837 	const int		dstRowPitch		= dst.getRowPitch();
838 	const int		dstPixelSize	= ETC2_UNCOMPRESSED_PIXEL_SIZE_RGBA8;
839 
840 	const deUint64	compressedBlockAlpha	= get128BitBlockStart(src, 0);
841 	const deUint64	compressedBlockRGB		= get128BitBlockEnd(src, 0);
842 	deUint8			uncompressedBlockAlpha[ETC2_UNCOMPRESSED_BLOCK_SIZE_A8];
843 	deUint8			uncompressedBlockRGB[ETC2_UNCOMPRESSED_BLOCK_SIZE_RGB8];
844 
845 	// Decompress.
846 	decompressETC2Block(uncompressedBlockRGB, compressedBlockRGB, NULL, false);
847 	decompressEAC8Block(uncompressedBlockAlpha, compressedBlockAlpha);
848 
849 	// Write to dst.
850 	for (int y = 0; y < (int)ETC2_BLOCK_HEIGHT; y++)
851 	{
852 		for (int x = 0; x < (int)ETC2_BLOCK_WIDTH; x++)
853 		{
854 			const deUint8* const	srcPixelRGB		= &uncompressedBlockRGB[(y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8];
855 			const deUint8* const	srcPixelAlpha	= &uncompressedBlockAlpha[(y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_A8];
856 			deUint8* const			dstPixel		= dstPtr + y*dstRowPitch + x*dstPixelSize;
857 
858 			DE_STATIC_ASSERT(ETC2_UNCOMPRESSED_PIXEL_SIZE_RGBA8 == 4);
859 			dstPixel[0] = srcPixelRGB[0];
860 			dstPixel[1] = srcPixelRGB[1];
861 			dstPixel[2] = srcPixelRGB[2];
862 			dstPixel[3] = srcPixelAlpha[0];
863 		}
864 	}
865 }
866 
decompressETC2_RGB8_PUNCHTHROUGH_ALPHA1(const PixelBufferAccess & dst,const deUint8 * src)867 void decompressETC2_RGB8_PUNCHTHROUGH_ALPHA1 (const PixelBufferAccess& dst, const deUint8* src)
868 {
869 	using namespace EtcDecompressInternal;
870 
871 	deUint8* const	dstPtr			= (deUint8*)dst.getDataPtr();
872 	const int		dstRowPitch		= dst.getRowPitch();
873 	const int		dstPixelSize	= ETC2_UNCOMPRESSED_PIXEL_SIZE_RGBA8;
874 
875 	const deUint64	compressedBlockRGBA	= get64BitBlock(src, 0);
876 	deUint8			uncompressedBlockRGB[ETC2_UNCOMPRESSED_BLOCK_SIZE_RGB8];
877 	deUint8			uncompressedBlockAlpha[ETC2_UNCOMPRESSED_BLOCK_SIZE_A8];
878 
879 	// Decompress.
880 	decompressETC2Block(uncompressedBlockRGB, compressedBlockRGBA, uncompressedBlockAlpha, DE_TRUE);
881 
882 	// Write to dst.
883 	for (int y = 0; y < (int)ETC2_BLOCK_HEIGHT; y++)
884 	{
885 		for (int x = 0; x < (int)ETC2_BLOCK_WIDTH; x++)
886 		{
887 			const deUint8* const	srcPixel		= &uncompressedBlockRGB[(y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8];
888 			const deUint8* const	srcPixelAlpha	= &uncompressedBlockAlpha[(y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_A8];
889 			deUint8* const			dstPixel		= dstPtr + y*dstRowPitch + x*dstPixelSize;
890 
891 			DE_STATIC_ASSERT(ETC2_UNCOMPRESSED_PIXEL_SIZE_RGBA8 == 4);
892 			dstPixel[0] = srcPixel[0];
893 			dstPixel[1] = srcPixel[1];
894 			dstPixel[2] = srcPixel[2];
895 			dstPixel[3] = srcPixelAlpha[0];
896 		}
897 	}
898 }
899 
decompressEAC_R11(const PixelBufferAccess & dst,const deUint8 * src,bool signedMode)900 void decompressEAC_R11 (const PixelBufferAccess& dst, const deUint8* src, bool signedMode)
901 {
902 	using namespace EtcDecompressInternal;
903 
904 	deUint8* const	dstPtr			= (deUint8*)dst.getDataPtr();
905 	const int		dstRowPitch		= dst.getRowPitch();
906 	const int		dstPixelSize	= ETC2_UNCOMPRESSED_PIXEL_SIZE_R11;
907 
908 	const deUint64	compressedBlock = get64BitBlock(src, 0);
909 	deUint8			uncompressedBlock[ETC2_UNCOMPRESSED_BLOCK_SIZE_R11];
910 
911 	// Decompress.
912 	decompressEAC11Block(uncompressedBlock, compressedBlock, signedMode);
913 
914 	// Write to dst.
915 	for (int y = 0; y < (int)ETC2_BLOCK_HEIGHT; y++)
916 	{
917 		for (int x = 0; x < (int)ETC2_BLOCK_WIDTH; x++)
918 		{
919 			DE_STATIC_ASSERT(ETC2_UNCOMPRESSED_PIXEL_SIZE_R11 == 2);
920 
921 			if (signedMode)
922 			{
923 				const deInt16* const	srcPixel = (deInt16*)&uncompressedBlock[(y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_R11];
924 				deInt16* const			dstPixel = (deInt16*)(dstPtr + y*dstRowPitch + x*dstPixelSize);
925 
926 				dstPixel[0] = extend11To16WithSign(srcPixel[0]);
927 			}
928 			else
929 			{
930 				const deUint16* const	srcPixel = (deUint16*)&uncompressedBlock[(y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_R11];
931 				deUint16* const			dstPixel = (deUint16*)(dstPtr + y*dstRowPitch + x*dstPixelSize);
932 
933 				dstPixel[0] = extend11To16(srcPixel[0]);
934 			}
935 		}
936 	}
937 }
938 
decompressEAC_RG11(const PixelBufferAccess & dst,const deUint8 * src,bool signedMode)939 void decompressEAC_RG11 (const PixelBufferAccess& dst, const deUint8* src, bool signedMode)
940 {
941 	using namespace EtcDecompressInternal;
942 
943 	deUint8* const	dstPtr			= (deUint8*)dst.getDataPtr();
944 	const int		dstRowPitch		= dst.getRowPitch();
945 	const int		dstPixelSize	= ETC2_UNCOMPRESSED_PIXEL_SIZE_RG11;
946 
947 	const deUint64	compressedBlockR = get128BitBlockStart(src, 0);
948 	const deUint64	compressedBlockG = get128BitBlockEnd(src, 0);
949 	deUint8			uncompressedBlockR[ETC2_UNCOMPRESSED_BLOCK_SIZE_R11];
950 	deUint8			uncompressedBlockG[ETC2_UNCOMPRESSED_BLOCK_SIZE_R11];
951 
952 	// Decompress.
953 	decompressEAC11Block(uncompressedBlockR, compressedBlockR, signedMode);
954 	decompressEAC11Block(uncompressedBlockG, compressedBlockG, signedMode);
955 
956 	// Write to dst.
957 	for (int y = 0; y < (int)ETC2_BLOCK_HEIGHT; y++)
958 	{
959 		for (int x = 0; x < (int)ETC2_BLOCK_WIDTH; x++)
960 		{
961 			DE_STATIC_ASSERT(ETC2_UNCOMPRESSED_PIXEL_SIZE_RG11 == 4);
962 
963 			if (signedMode)
964 			{
965 				const deInt16* const	srcPixelR	= (deInt16*)&uncompressedBlockR[(y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_R11];
966 				const deInt16* const	srcPixelG	= (deInt16*)&uncompressedBlockG[(y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_R11];
967 				deInt16* const			dstPixel	= (deInt16*)(dstPtr + y*dstRowPitch + x*dstPixelSize);
968 
969 				dstPixel[0] = extend11To16WithSign(srcPixelR[0]);
970 				dstPixel[1] = extend11To16WithSign(srcPixelG[0]);
971 			}
972 			else
973 			{
974 				const deUint16* const	srcPixelR	= (deUint16*)&uncompressedBlockR[(y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_R11];
975 				const deUint16* const	srcPixelG	= (deUint16*)&uncompressedBlockG[(y*ETC2_BLOCK_WIDTH + x)*ETC2_UNCOMPRESSED_PIXEL_SIZE_R11];
976 				deUint16* const			dstPixel	= (deUint16*)(dstPtr + y*dstRowPitch + x*dstPixelSize);
977 
978 				dstPixel[0] = extend11To16(srcPixelR[0]);
979 				dstPixel[1] = extend11To16(srcPixelG[0]);
980 			}
981 		}
982 	}
983 }
984 
decompressBlock(CompressedTexFormat format,const PixelBufferAccess & dst,const deUint8 * src,const TexDecompressionParams & params)985 void decompressBlock (CompressedTexFormat format, const PixelBufferAccess& dst, const deUint8* src, const TexDecompressionParams& params)
986 {
987 	// No 3D blocks supported right now
988 	DE_ASSERT(dst.getDepth() == 1);
989 
990 	switch (format)
991 	{
992 		case COMPRESSEDTEXFORMAT_ETC1_RGB8:							decompressETC1							(dst, src);			break;
993 		case COMPRESSEDTEXFORMAT_EAC_R11:							decompressEAC_R11						(dst, src, false);	break;
994 		case COMPRESSEDTEXFORMAT_EAC_SIGNED_R11:					decompressEAC_R11						(dst, src, true);	break;
995 		case COMPRESSEDTEXFORMAT_EAC_RG11:							decompressEAC_RG11						(dst, src, false);	break;
996 		case COMPRESSEDTEXFORMAT_EAC_SIGNED_RG11:					decompressEAC_RG11						(dst, src, true);	break;
997 		case COMPRESSEDTEXFORMAT_ETC2_RGB8:							decompressETC2							(dst, src);			break;
998 		case COMPRESSEDTEXFORMAT_ETC2_SRGB8:						decompressETC2							(dst, src);			break;
999 		case COMPRESSEDTEXFORMAT_ETC2_RGB8_PUNCHTHROUGH_ALPHA1:		decompressETC2_RGB8_PUNCHTHROUGH_ALPHA1	(dst, src);			break;
1000 		case COMPRESSEDTEXFORMAT_ETC2_SRGB8_PUNCHTHROUGH_ALPHA1:	decompressETC2_RGB8_PUNCHTHROUGH_ALPHA1	(dst, src);			break;
1001 		case COMPRESSEDTEXFORMAT_ETC2_EAC_RGBA8:					decompressETC2_EAC_RGBA8				(dst, src);			break;
1002 		case COMPRESSEDTEXFORMAT_ETC2_EAC_SRGB8_ALPHA8:				decompressETC2_EAC_RGBA8				(dst, src);			break;
1003 
1004 		case COMPRESSEDTEXFORMAT_ASTC_4x4_RGBA:
1005 		case COMPRESSEDTEXFORMAT_ASTC_5x4_RGBA:
1006 		case COMPRESSEDTEXFORMAT_ASTC_5x5_RGBA:
1007 		case COMPRESSEDTEXFORMAT_ASTC_6x5_RGBA:
1008 		case COMPRESSEDTEXFORMAT_ASTC_6x6_RGBA:
1009 		case COMPRESSEDTEXFORMAT_ASTC_8x5_RGBA:
1010 		case COMPRESSEDTEXFORMAT_ASTC_8x6_RGBA:
1011 		case COMPRESSEDTEXFORMAT_ASTC_8x8_RGBA:
1012 		case COMPRESSEDTEXFORMAT_ASTC_10x5_RGBA:
1013 		case COMPRESSEDTEXFORMAT_ASTC_10x6_RGBA:
1014 		case COMPRESSEDTEXFORMAT_ASTC_10x8_RGBA:
1015 		case COMPRESSEDTEXFORMAT_ASTC_10x10_RGBA:
1016 		case COMPRESSEDTEXFORMAT_ASTC_12x10_RGBA:
1017 		case COMPRESSEDTEXFORMAT_ASTC_12x12_RGBA:
1018 		case COMPRESSEDTEXFORMAT_ASTC_4x4_SRGB8_ALPHA8:
1019 		case COMPRESSEDTEXFORMAT_ASTC_5x4_SRGB8_ALPHA8:
1020 		case COMPRESSEDTEXFORMAT_ASTC_5x5_SRGB8_ALPHA8:
1021 		case COMPRESSEDTEXFORMAT_ASTC_6x5_SRGB8_ALPHA8:
1022 		case COMPRESSEDTEXFORMAT_ASTC_6x6_SRGB8_ALPHA8:
1023 		case COMPRESSEDTEXFORMAT_ASTC_8x5_SRGB8_ALPHA8:
1024 		case COMPRESSEDTEXFORMAT_ASTC_8x6_SRGB8_ALPHA8:
1025 		case COMPRESSEDTEXFORMAT_ASTC_8x8_SRGB8_ALPHA8:
1026 		case COMPRESSEDTEXFORMAT_ASTC_10x5_SRGB8_ALPHA8:
1027 		case COMPRESSEDTEXFORMAT_ASTC_10x6_SRGB8_ALPHA8:
1028 		case COMPRESSEDTEXFORMAT_ASTC_10x8_SRGB8_ALPHA8:
1029 		case COMPRESSEDTEXFORMAT_ASTC_10x10_SRGB8_ALPHA8:
1030 		case COMPRESSEDTEXFORMAT_ASTC_12x10_SRGB8_ALPHA8:
1031 		case COMPRESSEDTEXFORMAT_ASTC_12x12_SRGB8_ALPHA8:
1032 			astc::decompress(dst, src, format, params.astcMode);
1033 			break;
1034 
1035 		default:
1036 			DE_ASSERT(false);
1037 			break;
1038 	}
1039 }
1040 
componentSum(const IVec3 & vec)1041 int componentSum (const IVec3& vec)
1042 {
1043 	return vec.x() + vec.y() + vec.z();
1044 }
1045 
1046 } // anonymous
1047 
decompress(const PixelBufferAccess & dst,CompressedTexFormat fmt,const deUint8 * src,const TexDecompressionParams & params)1048 void decompress (const PixelBufferAccess& dst, CompressedTexFormat fmt, const deUint8* src, const TexDecompressionParams& params)
1049 {
1050 	const int				blockSize			= getBlockSize(fmt);
1051 	const IVec3				blockPixelSize		(getBlockPixelSize(fmt));
1052 	const IVec3				blockCount			(deDivRoundUp32(dst.getWidth(),		blockPixelSize.x()),
1053 												 deDivRoundUp32(dst.getHeight(),	blockPixelSize.y()),
1054 												 deDivRoundUp32(dst.getDepth(),		blockPixelSize.z()));
1055 	const IVec3				blockPitches		(blockSize, blockSize * blockCount.x(), blockSize * blockCount.x() * blockCount.y());
1056 
1057 	std::vector<deUint8>	uncompressedBlock	(dst.getFormat().getPixelSize() * blockPixelSize.x() * blockPixelSize.y() * blockPixelSize.z());
1058 	const PixelBufferAccess	blockAccess			(getUncompressedFormat(fmt), blockPixelSize.x(), blockPixelSize.y(), blockPixelSize.z(), &uncompressedBlock[0]);
1059 
1060 	DE_ASSERT(dst.getFormat() == getUncompressedFormat(fmt));
1061 
1062 	for (int blockZ = 0; blockZ < blockCount.z(); blockZ++)
1063 	for (int blockY = 0; blockY < blockCount.y(); blockY++)
1064 	for (int blockX = 0; blockX < blockCount.x(); blockX++)
1065 	{
1066 		const IVec3				blockPos	(blockX, blockY, blockZ);
1067 		const deUint8* const	blockPtr	= src + componentSum(blockPos * blockPitches);
1068 		const IVec3				copySize	(de::min(blockPixelSize.x(), dst.getWidth()		- blockPos.x() * blockPixelSize.x()),
1069 											 de::min(blockPixelSize.y(), dst.getHeight()	- blockPos.y() * blockPixelSize.y()),
1070 											 de::min(blockPixelSize.z(), dst.getDepth()		- blockPos.z() * blockPixelSize.z()));
1071 		const IVec3				dstPixelPos	= blockPos * blockPixelSize;
1072 
1073 		decompressBlock(fmt, blockAccess, blockPtr, params);
1074 
1075 		copy(getSubregion(dst, dstPixelPos.x(), dstPixelPos.y(), dstPixelPos.z(), copySize.x(), copySize.y(), copySize.z()), getSubregion(blockAccess, 0, 0, 0, copySize.x(), copySize.y(), copySize.z()));
1076 	}
1077 }
1078 
CompressedTexture(void)1079 CompressedTexture::CompressedTexture (void)
1080 	: m_format	(COMPRESSEDTEXFORMAT_LAST)
1081 	, m_width	(0)
1082 	, m_height	(0)
1083 	, m_depth	(0)
1084 {
1085 }
1086 
CompressedTexture(CompressedTexFormat format,int width,int height,int depth)1087 CompressedTexture::CompressedTexture (CompressedTexFormat format, int width, int height, int depth)
1088 	: m_format	(COMPRESSEDTEXFORMAT_LAST)
1089 	, m_width	(0)
1090 	, m_height	(0)
1091 	, m_depth	(0)
1092 {
1093 	setStorage(format, width, height, depth);
1094 }
1095 
~CompressedTexture(void)1096 CompressedTexture::~CompressedTexture (void)
1097 {
1098 }
1099 
setStorage(CompressedTexFormat format,int width,int height,int depth)1100 void CompressedTexture::setStorage (CompressedTexFormat format, int width, int height, int depth)
1101 {
1102 	m_format	= format;
1103 	m_width		= width;
1104 	m_height	= height;
1105 	m_depth		= depth;
1106 
1107 	if (m_format != COMPRESSEDTEXFORMAT_LAST)
1108 	{
1109 		const IVec3	blockPixelSize	= getBlockPixelSize(m_format);
1110 		const int	blockSize		= getBlockSize(m_format);
1111 
1112 		m_data.resize(deDivRoundUp32(m_width, blockPixelSize.x()) * deDivRoundUp32(m_height, blockPixelSize.y()) * deDivRoundUp32(m_depth, blockPixelSize.z()) * blockSize);
1113 	}
1114 	else
1115 	{
1116 		DE_ASSERT(m_format == COMPRESSEDTEXFORMAT_LAST);
1117 		DE_ASSERT(m_width == 0 && m_height == 0 && m_depth == 0);
1118 		m_data.resize(0);
1119 	}
1120 }
1121 
1122 /*--------------------------------------------------------------------*//*!
1123  * \brief Decode to uncompressed pixel data
1124  * \param dst Destination buffer
1125  *//*--------------------------------------------------------------------*/
decompress(const PixelBufferAccess & dst,const TexDecompressionParams & params) const1126 void CompressedTexture::decompress (const PixelBufferAccess& dst, const TexDecompressionParams& params) const
1127 {
1128 	DE_ASSERT(dst.getWidth() == m_width && dst.getHeight() == m_height && dst.getDepth() == m_depth);
1129 	DE_ASSERT(dst.getFormat() == getUncompressedFormat(m_format));
1130 
1131 	tcu::decompress(dst, m_format, &m_data[0], params);
1132 }
1133 
1134 } // tcu
1135