1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Texture block decompression 3cabdff1aSopenharmony_ci * Copyright (C) 2009 Benjamin Dobell, Glass Echidna 4cabdff1aSopenharmony_ci * Copyright (C) 2012 Matthäus G. "Anteru" Chajdas (http://anteru.net) 5cabdff1aSopenharmony_ci * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com> 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 8cabdff1aSopenharmony_ci * copy of this software and associated documentation files (the "Software"), 9cabdff1aSopenharmony_ci * to deal in the Software without restriction, including without limitation 10cabdff1aSopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11cabdff1aSopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 12cabdff1aSopenharmony_ci * Software is furnished to do so, subject to the following conditions: 13cabdff1aSopenharmony_ci * The above copyright notice and this permission notice shall be included 14cabdff1aSopenharmony_ci * in all copies or substantial portions of the Software. 15cabdff1aSopenharmony_ci * 16cabdff1aSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17cabdff1aSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18cabdff1aSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19cabdff1aSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20cabdff1aSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21cabdff1aSopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22cabdff1aSopenharmony_ci * IN THE SOFTWARE. 23cabdff1aSopenharmony_ci */ 24cabdff1aSopenharmony_ci 25cabdff1aSopenharmony_ci#include <stddef.h> 26cabdff1aSopenharmony_ci#include <stdint.h> 27cabdff1aSopenharmony_ci 28cabdff1aSopenharmony_ci#include "libavutil/attributes.h" 29cabdff1aSopenharmony_ci#include "libavutil/common.h" 30cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 31cabdff1aSopenharmony_ci#include "libavutil/libm.h" 32cabdff1aSopenharmony_ci 33cabdff1aSopenharmony_ci#include "texturedsp.h" 34cabdff1aSopenharmony_ci 35cabdff1aSopenharmony_ci#define RGBA(r, g, b, a) (((uint8_t)(r) << 0) | \ 36cabdff1aSopenharmony_ci ((uint8_t)(g) << 8) | \ 37cabdff1aSopenharmony_ci ((uint8_t)(b) << 16) | \ 38cabdff1aSopenharmony_ci ((unsigned)(uint8_t)(a) << 24)) 39cabdff1aSopenharmony_ci 40cabdff1aSopenharmony_cistatic av_always_inline void extract_color(uint32_t colors[4], 41cabdff1aSopenharmony_ci uint16_t color0, 42cabdff1aSopenharmony_ci uint16_t color1, 43cabdff1aSopenharmony_ci int dxtn, int alpha) 44cabdff1aSopenharmony_ci{ 45cabdff1aSopenharmony_ci int tmp; 46cabdff1aSopenharmony_ci uint8_t r0, g0, b0, r1, g1, b1; 47cabdff1aSopenharmony_ci uint8_t a = dxtn ? 0 : 255; 48cabdff1aSopenharmony_ci 49cabdff1aSopenharmony_ci tmp = (color0 >> 11) * 255 + 16; 50cabdff1aSopenharmony_ci r0 = (uint8_t) ((tmp / 32 + tmp) / 32); 51cabdff1aSopenharmony_ci tmp = ((color0 & 0x07E0) >> 5) * 255 + 32; 52cabdff1aSopenharmony_ci g0 = (uint8_t) ((tmp / 64 + tmp) / 64); 53cabdff1aSopenharmony_ci tmp = (color0 & 0x001F) * 255 + 16; 54cabdff1aSopenharmony_ci b0 = (uint8_t) ((tmp / 32 + tmp) / 32); 55cabdff1aSopenharmony_ci 56cabdff1aSopenharmony_ci tmp = (color1 >> 11) * 255 + 16; 57cabdff1aSopenharmony_ci r1 = (uint8_t) ((tmp / 32 + tmp) / 32); 58cabdff1aSopenharmony_ci tmp = ((color1 & 0x07E0) >> 5) * 255 + 32; 59cabdff1aSopenharmony_ci g1 = (uint8_t) ((tmp / 64 + tmp) / 64); 60cabdff1aSopenharmony_ci tmp = (color1 & 0x001F) * 255 + 16; 61cabdff1aSopenharmony_ci b1 = (uint8_t) ((tmp / 32 + tmp) / 32); 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_ci if (dxtn || color0 > color1) { 64cabdff1aSopenharmony_ci colors[0] = RGBA(r0, g0, b0, a); 65cabdff1aSopenharmony_ci colors[1] = RGBA(r1, g1, b1, a); 66cabdff1aSopenharmony_ci colors[2] = RGBA((2 * r0 + r1) / 3, 67cabdff1aSopenharmony_ci (2 * g0 + g1) / 3, 68cabdff1aSopenharmony_ci (2 * b0 + b1) / 3, 69cabdff1aSopenharmony_ci a); 70cabdff1aSopenharmony_ci colors[3] = RGBA((2 * r1 + r0) / 3, 71cabdff1aSopenharmony_ci (2 * g1 + g0) / 3, 72cabdff1aSopenharmony_ci (2 * b1 + b0) / 3, 73cabdff1aSopenharmony_ci a); 74cabdff1aSopenharmony_ci } else { 75cabdff1aSopenharmony_ci colors[0] = RGBA(r0, g0, b0, a); 76cabdff1aSopenharmony_ci colors[1] = RGBA(r1, g1, b1, a); 77cabdff1aSopenharmony_ci colors[2] = RGBA((r0 + r1) / 2, 78cabdff1aSopenharmony_ci (g0 + g1) / 2, 79cabdff1aSopenharmony_ci (b0 + b1) / 2, 80cabdff1aSopenharmony_ci a); 81cabdff1aSopenharmony_ci colors[3] = RGBA(0, 0, 0, alpha); 82cabdff1aSopenharmony_ci } 83cabdff1aSopenharmony_ci} 84cabdff1aSopenharmony_ci 85cabdff1aSopenharmony_cistatic inline void dxt1_block_internal(uint8_t *dst, ptrdiff_t stride, 86cabdff1aSopenharmony_ci const uint8_t *block, uint8_t alpha) 87cabdff1aSopenharmony_ci{ 88cabdff1aSopenharmony_ci int x, y; 89cabdff1aSopenharmony_ci uint32_t colors[4]; 90cabdff1aSopenharmony_ci uint16_t color0 = AV_RL16(block + 0); 91cabdff1aSopenharmony_ci uint16_t color1 = AV_RL16(block + 2); 92cabdff1aSopenharmony_ci uint32_t code = AV_RL32(block + 4); 93cabdff1aSopenharmony_ci 94cabdff1aSopenharmony_ci extract_color(colors, color0, color1, 0, alpha); 95cabdff1aSopenharmony_ci 96cabdff1aSopenharmony_ci for (y = 0; y < 4; y++) { 97cabdff1aSopenharmony_ci for (x = 0; x < 4; x++) { 98cabdff1aSopenharmony_ci uint32_t pixel = colors[code & 3]; 99cabdff1aSopenharmony_ci code >>= 2; 100cabdff1aSopenharmony_ci AV_WL32(dst + x * 4, pixel); 101cabdff1aSopenharmony_ci } 102cabdff1aSopenharmony_ci dst += stride; 103cabdff1aSopenharmony_ci } 104cabdff1aSopenharmony_ci} 105cabdff1aSopenharmony_ci 106cabdff1aSopenharmony_ci/** 107cabdff1aSopenharmony_ci * Decompress one block of a DXT1 texture and store the resulting 108cabdff1aSopenharmony_ci * RGBA pixels in 'dst'. Alpha component is fully opaque. 109cabdff1aSopenharmony_ci * 110cabdff1aSopenharmony_ci * @param dst output buffer. 111cabdff1aSopenharmony_ci * @param stride scanline in bytes. 112cabdff1aSopenharmony_ci * @param block block to decompress. 113cabdff1aSopenharmony_ci * @return how much texture data has been consumed. 114cabdff1aSopenharmony_ci */ 115cabdff1aSopenharmony_cistatic int dxt1_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) 116cabdff1aSopenharmony_ci{ 117cabdff1aSopenharmony_ci dxt1_block_internal(dst, stride, block, 255); 118cabdff1aSopenharmony_ci 119cabdff1aSopenharmony_ci return 8; 120cabdff1aSopenharmony_ci} 121cabdff1aSopenharmony_ci 122cabdff1aSopenharmony_ci/** 123cabdff1aSopenharmony_ci * Decompress one block of a DXT1 with 1-bit alpha texture and store 124cabdff1aSopenharmony_ci * the resulting RGBA pixels in 'dst'. Alpha is either fully opaque or 125cabdff1aSopenharmony_ci * fully transparent. 126cabdff1aSopenharmony_ci * 127cabdff1aSopenharmony_ci * @param dst output buffer. 128cabdff1aSopenharmony_ci * @param stride scanline in bytes. 129cabdff1aSopenharmony_ci * @param block block to decompress. 130cabdff1aSopenharmony_ci * @return how much texture data has been consumed. 131cabdff1aSopenharmony_ci */ 132cabdff1aSopenharmony_cistatic int dxt1a_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) 133cabdff1aSopenharmony_ci{ 134cabdff1aSopenharmony_ci dxt1_block_internal(dst, stride, block, 0); 135cabdff1aSopenharmony_ci 136cabdff1aSopenharmony_ci return 8; 137cabdff1aSopenharmony_ci} 138cabdff1aSopenharmony_ci 139cabdff1aSopenharmony_cistatic inline void dxt3_block_internal(uint8_t *dst, ptrdiff_t stride, 140cabdff1aSopenharmony_ci const uint8_t *block) 141cabdff1aSopenharmony_ci{ 142cabdff1aSopenharmony_ci int x, y; 143cabdff1aSopenharmony_ci uint32_t colors[4]; 144cabdff1aSopenharmony_ci uint16_t color0 = AV_RL16(block + 8); 145cabdff1aSopenharmony_ci uint16_t color1 = AV_RL16(block + 10); 146cabdff1aSopenharmony_ci uint32_t code = AV_RL32(block + 12); 147cabdff1aSopenharmony_ci 148cabdff1aSopenharmony_ci extract_color(colors, color0, color1, 1, 0); 149cabdff1aSopenharmony_ci 150cabdff1aSopenharmony_ci for (y = 0; y < 4; y++) { 151cabdff1aSopenharmony_ci const uint16_t alpha_code = AV_RL16(block + 2 * y); 152cabdff1aSopenharmony_ci uint8_t alpha_values[4]; 153cabdff1aSopenharmony_ci 154cabdff1aSopenharmony_ci alpha_values[0] = ((alpha_code >> 0) & 0x0F) * 17; 155cabdff1aSopenharmony_ci alpha_values[1] = ((alpha_code >> 4) & 0x0F) * 17; 156cabdff1aSopenharmony_ci alpha_values[2] = ((alpha_code >> 8) & 0x0F) * 17; 157cabdff1aSopenharmony_ci alpha_values[3] = ((alpha_code >> 12) & 0x0F) * 17; 158cabdff1aSopenharmony_ci 159cabdff1aSopenharmony_ci for (x = 0; x < 4; x++) { 160cabdff1aSopenharmony_ci uint8_t alpha = alpha_values[x]; 161cabdff1aSopenharmony_ci uint32_t pixel = colors[code & 3] | ((unsigned)alpha << 24); 162cabdff1aSopenharmony_ci code >>= 2; 163cabdff1aSopenharmony_ci 164cabdff1aSopenharmony_ci AV_WL32(dst + x * 4, pixel); 165cabdff1aSopenharmony_ci } 166cabdff1aSopenharmony_ci dst += stride; 167cabdff1aSopenharmony_ci } 168cabdff1aSopenharmony_ci} 169cabdff1aSopenharmony_ci 170cabdff1aSopenharmony_ci/** Convert a premultiplied alpha pixel to a straight alpha pixel. */ 171cabdff1aSopenharmony_cistatic av_always_inline void premult2straight(uint8_t *src) 172cabdff1aSopenharmony_ci{ 173cabdff1aSopenharmony_ci int r = src[0]; 174cabdff1aSopenharmony_ci int g = src[1]; 175cabdff1aSopenharmony_ci int b = src[2]; 176cabdff1aSopenharmony_ci int a = src[3]; /* unchanged */ 177cabdff1aSopenharmony_ci 178cabdff1aSopenharmony_ci src[0] = (uint8_t) r * a / 255; 179cabdff1aSopenharmony_ci src[1] = (uint8_t) g * a / 255; 180cabdff1aSopenharmony_ci src[2] = (uint8_t) b * a / 255; 181cabdff1aSopenharmony_ci} 182cabdff1aSopenharmony_ci 183cabdff1aSopenharmony_ci/** 184cabdff1aSopenharmony_ci * Decompress one block of a DXT2 texture and store the resulting 185cabdff1aSopenharmony_ci * RGBA pixels in 'dst'. 186cabdff1aSopenharmony_ci * 187cabdff1aSopenharmony_ci * @param dst output buffer. 188cabdff1aSopenharmony_ci * @param stride scanline in bytes. 189cabdff1aSopenharmony_ci * @param block block to decompress. 190cabdff1aSopenharmony_ci * @return how much texture data has been consumed. 191cabdff1aSopenharmony_ci */ 192cabdff1aSopenharmony_cistatic int dxt2_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) 193cabdff1aSopenharmony_ci{ 194cabdff1aSopenharmony_ci int x, y; 195cabdff1aSopenharmony_ci 196cabdff1aSopenharmony_ci dxt3_block_internal(dst, stride, block); 197cabdff1aSopenharmony_ci 198cabdff1aSopenharmony_ci /* This format is DXT3, but returns premultiplied alpha. It needs to be 199cabdff1aSopenharmony_ci * converted because it's what lavc outputs (and swscale expects). */ 200cabdff1aSopenharmony_ci for (y = 0; y < 4; y++) 201cabdff1aSopenharmony_ci for (x = 0; x < 4; x++) 202cabdff1aSopenharmony_ci premult2straight(dst + x * 4 + y * stride); 203cabdff1aSopenharmony_ci 204cabdff1aSopenharmony_ci return 16; 205cabdff1aSopenharmony_ci} 206cabdff1aSopenharmony_ci 207cabdff1aSopenharmony_ci/** 208cabdff1aSopenharmony_ci * Decompress one block of a DXT3 texture and store the resulting 209cabdff1aSopenharmony_ci * RGBA pixels in 'dst'. 210cabdff1aSopenharmony_ci * 211cabdff1aSopenharmony_ci * @param dst output buffer. 212cabdff1aSopenharmony_ci * @param stride scanline in bytes. 213cabdff1aSopenharmony_ci * @param block block to decompress. 214cabdff1aSopenharmony_ci * @return how much texture data has been consumed. 215cabdff1aSopenharmony_ci */ 216cabdff1aSopenharmony_cistatic int dxt3_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) 217cabdff1aSopenharmony_ci{ 218cabdff1aSopenharmony_ci dxt3_block_internal(dst, stride, block); 219cabdff1aSopenharmony_ci 220cabdff1aSopenharmony_ci return 16; 221cabdff1aSopenharmony_ci} 222cabdff1aSopenharmony_ci 223cabdff1aSopenharmony_ci/** 224cabdff1aSopenharmony_ci * Decompress a BC 16x3 index block stored as 225cabdff1aSopenharmony_ci * h g f e 226cabdff1aSopenharmony_ci * d c b a 227cabdff1aSopenharmony_ci * p o n m 228cabdff1aSopenharmony_ci * l k j i 229cabdff1aSopenharmony_ci * 230cabdff1aSopenharmony_ci * Bits packed as 231cabdff1aSopenharmony_ci * | h | g | f | e | d | c | b | a | // Entry 232cabdff1aSopenharmony_ci * |765 432 107 654 321 076 543 210| // Bit 233cabdff1aSopenharmony_ci * |0000000000111111111112222222222| // Byte 234cabdff1aSopenharmony_ci * 235cabdff1aSopenharmony_ci * into 16 8-bit indices. 236cabdff1aSopenharmony_ci */ 237cabdff1aSopenharmony_cistatic void decompress_indices(uint8_t *dst, const uint8_t *src) 238cabdff1aSopenharmony_ci{ 239cabdff1aSopenharmony_ci int block, i; 240cabdff1aSopenharmony_ci 241cabdff1aSopenharmony_ci for (block = 0; block < 2; block++) { 242cabdff1aSopenharmony_ci int tmp = AV_RL24(src); 243cabdff1aSopenharmony_ci 244cabdff1aSopenharmony_ci /* Unpack 8x3 bit from last 3 byte block */ 245cabdff1aSopenharmony_ci for (i = 0; i < 8; i++) 246cabdff1aSopenharmony_ci dst[i] = (tmp >> (i * 3)) & 0x7; 247cabdff1aSopenharmony_ci 248cabdff1aSopenharmony_ci src += 3; 249cabdff1aSopenharmony_ci dst += 8; 250cabdff1aSopenharmony_ci } 251cabdff1aSopenharmony_ci} 252cabdff1aSopenharmony_ci 253cabdff1aSopenharmony_cistatic inline void dxt5_block_internal(uint8_t *dst, ptrdiff_t stride, 254cabdff1aSopenharmony_ci const uint8_t *block) 255cabdff1aSopenharmony_ci{ 256cabdff1aSopenharmony_ci int x, y; 257cabdff1aSopenharmony_ci uint32_t colors[4]; 258cabdff1aSopenharmony_ci uint8_t alpha_indices[16]; 259cabdff1aSopenharmony_ci uint16_t color0 = AV_RL16(block + 8); 260cabdff1aSopenharmony_ci uint16_t color1 = AV_RL16(block + 10); 261cabdff1aSopenharmony_ci uint32_t code = AV_RL32(block + 12); 262cabdff1aSopenharmony_ci uint8_t alpha0 = *(block); 263cabdff1aSopenharmony_ci uint8_t alpha1 = *(block + 1); 264cabdff1aSopenharmony_ci 265cabdff1aSopenharmony_ci decompress_indices(alpha_indices, block + 2); 266cabdff1aSopenharmony_ci 267cabdff1aSopenharmony_ci extract_color(colors, color0, color1, 1, 0); 268cabdff1aSopenharmony_ci 269cabdff1aSopenharmony_ci for (y = 0; y < 4; y++) { 270cabdff1aSopenharmony_ci for (x = 0; x < 4; x++) { 271cabdff1aSopenharmony_ci int alpha_code = alpha_indices[x + y * 4]; 272cabdff1aSopenharmony_ci uint32_t pixel; 273cabdff1aSopenharmony_ci uint8_t alpha; 274cabdff1aSopenharmony_ci 275cabdff1aSopenharmony_ci if (alpha_code == 0) { 276cabdff1aSopenharmony_ci alpha = alpha0; 277cabdff1aSopenharmony_ci } else if (alpha_code == 1) { 278cabdff1aSopenharmony_ci alpha = alpha1; 279cabdff1aSopenharmony_ci } else { 280cabdff1aSopenharmony_ci if (alpha0 > alpha1) { 281cabdff1aSopenharmony_ci alpha = (uint8_t) (((8 - alpha_code) * alpha0 + 282cabdff1aSopenharmony_ci (alpha_code - 1) * alpha1) / 7); 283cabdff1aSopenharmony_ci } else { 284cabdff1aSopenharmony_ci if (alpha_code == 6) { 285cabdff1aSopenharmony_ci alpha = 0; 286cabdff1aSopenharmony_ci } else if (alpha_code == 7) { 287cabdff1aSopenharmony_ci alpha = 255; 288cabdff1aSopenharmony_ci } else { 289cabdff1aSopenharmony_ci alpha = (uint8_t) (((6 - alpha_code) * alpha0 + 290cabdff1aSopenharmony_ci (alpha_code - 1) * alpha1) / 5); 291cabdff1aSopenharmony_ci } 292cabdff1aSopenharmony_ci } 293cabdff1aSopenharmony_ci } 294cabdff1aSopenharmony_ci pixel = colors[code & 3] | ((unsigned)alpha << 24); 295cabdff1aSopenharmony_ci code >>= 2; 296cabdff1aSopenharmony_ci AV_WL32(dst + x * 4, pixel); 297cabdff1aSopenharmony_ci } 298cabdff1aSopenharmony_ci dst += stride; 299cabdff1aSopenharmony_ci } 300cabdff1aSopenharmony_ci} 301cabdff1aSopenharmony_ci 302cabdff1aSopenharmony_ci/** 303cabdff1aSopenharmony_ci * Decompress one block of a DXT4 texture and store the resulting 304cabdff1aSopenharmony_ci * RGBA pixels in 'dst'. 305cabdff1aSopenharmony_ci * 306cabdff1aSopenharmony_ci * @param dst output buffer. 307cabdff1aSopenharmony_ci * @param stride scanline in bytes. 308cabdff1aSopenharmony_ci * @param block block to decompress. 309cabdff1aSopenharmony_ci * @return how much texture data has been consumed. 310cabdff1aSopenharmony_ci */ 311cabdff1aSopenharmony_cistatic int dxt4_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) 312cabdff1aSopenharmony_ci{ 313cabdff1aSopenharmony_ci int x, y; 314cabdff1aSopenharmony_ci 315cabdff1aSopenharmony_ci dxt5_block_internal(dst, stride, block); 316cabdff1aSopenharmony_ci 317cabdff1aSopenharmony_ci /* This format is DXT5, but returns premultiplied alpha. It needs to be 318cabdff1aSopenharmony_ci * converted because it's what lavc outputs (and swscale expects). */ 319cabdff1aSopenharmony_ci for (y = 0; y < 4; y++) 320cabdff1aSopenharmony_ci for (x = 0; x < 4; x++) 321cabdff1aSopenharmony_ci premult2straight(dst + x * 4 + y * stride); 322cabdff1aSopenharmony_ci 323cabdff1aSopenharmony_ci return 16; 324cabdff1aSopenharmony_ci} 325cabdff1aSopenharmony_ci 326cabdff1aSopenharmony_ci/** 327cabdff1aSopenharmony_ci * Decompress one block of a DXT5 texture and store the resulting 328cabdff1aSopenharmony_ci * RGBA pixels in 'dst'. 329cabdff1aSopenharmony_ci * 330cabdff1aSopenharmony_ci * @param dst output buffer. 331cabdff1aSopenharmony_ci * @param stride scanline in bytes. 332cabdff1aSopenharmony_ci * @param block block to decompress. 333cabdff1aSopenharmony_ci * @return how much texture data has been consumed. 334cabdff1aSopenharmony_ci */ 335cabdff1aSopenharmony_cistatic int dxt5_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) 336cabdff1aSopenharmony_ci{ 337cabdff1aSopenharmony_ci dxt5_block_internal(dst, stride, block); 338cabdff1aSopenharmony_ci 339cabdff1aSopenharmony_ci return 16; 340cabdff1aSopenharmony_ci} 341cabdff1aSopenharmony_ci 342cabdff1aSopenharmony_ci/** 343cabdff1aSopenharmony_ci * Convert a YCoCg buffer to RGBA. 344cabdff1aSopenharmony_ci * 345cabdff1aSopenharmony_ci * @param src input buffer. 346cabdff1aSopenharmony_ci * @param scaled variant with scaled chroma components and opaque alpha. 347cabdff1aSopenharmony_ci */ 348cabdff1aSopenharmony_cistatic av_always_inline void ycocg2rgba(uint8_t *src, int scaled) 349cabdff1aSopenharmony_ci{ 350cabdff1aSopenharmony_ci int r = src[0]; 351cabdff1aSopenharmony_ci int g = src[1]; 352cabdff1aSopenharmony_ci int b = src[2]; 353cabdff1aSopenharmony_ci int a = src[3]; 354cabdff1aSopenharmony_ci 355cabdff1aSopenharmony_ci int s = scaled ? (b >> 3) + 1 : 1; 356cabdff1aSopenharmony_ci int y = a; 357cabdff1aSopenharmony_ci int co = (r - 128) / s; 358cabdff1aSopenharmony_ci int cg = (g - 128) / s; 359cabdff1aSopenharmony_ci 360cabdff1aSopenharmony_ci src[0] = av_clip_uint8(y + co - cg); 361cabdff1aSopenharmony_ci src[1] = av_clip_uint8(y + cg); 362cabdff1aSopenharmony_ci src[2] = av_clip_uint8(y - co - cg); 363cabdff1aSopenharmony_ci src[3] = scaled ? 255 : b; 364cabdff1aSopenharmony_ci} 365cabdff1aSopenharmony_ci 366cabdff1aSopenharmony_ci/** 367cabdff1aSopenharmony_ci * Decompress one block of a DXT5 texture with classic YCoCg and store 368cabdff1aSopenharmony_ci * the resulting RGBA pixels in 'dst'. Alpha component is fully opaque. 369cabdff1aSopenharmony_ci * 370cabdff1aSopenharmony_ci * @param dst output buffer. 371cabdff1aSopenharmony_ci * @param stride scanline in bytes. 372cabdff1aSopenharmony_ci * @param block block to decompress. 373cabdff1aSopenharmony_ci * @return how much texture data has been consumed. 374cabdff1aSopenharmony_ci */ 375cabdff1aSopenharmony_cistatic int dxt5y_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) 376cabdff1aSopenharmony_ci{ 377cabdff1aSopenharmony_ci int x, y; 378cabdff1aSopenharmony_ci 379cabdff1aSopenharmony_ci /* This format is basically DXT5, with luma stored in alpha. 380cabdff1aSopenharmony_ci * Run a normal decompress and then reorder the components. */ 381cabdff1aSopenharmony_ci dxt5_block_internal(dst, stride, block); 382cabdff1aSopenharmony_ci 383cabdff1aSopenharmony_ci for (y = 0; y < 4; y++) 384cabdff1aSopenharmony_ci for (x = 0; x < 4; x++) 385cabdff1aSopenharmony_ci ycocg2rgba(dst + x * 4 + y * stride, 0); 386cabdff1aSopenharmony_ci 387cabdff1aSopenharmony_ci return 16; 388cabdff1aSopenharmony_ci} 389cabdff1aSopenharmony_ci 390cabdff1aSopenharmony_ci/** 391cabdff1aSopenharmony_ci * Decompress one block of a DXT5 texture with scaled YCoCg and store 392cabdff1aSopenharmony_ci * the resulting RGBA pixels in 'dst'. Alpha component is fully opaque. 393cabdff1aSopenharmony_ci * 394cabdff1aSopenharmony_ci * @param dst output buffer. 395cabdff1aSopenharmony_ci * @param stride scanline in bytes. 396cabdff1aSopenharmony_ci * @param block block to decompress. 397cabdff1aSopenharmony_ci * @return how much texture data has been consumed. 398cabdff1aSopenharmony_ci */ 399cabdff1aSopenharmony_cistatic int dxt5ys_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) 400cabdff1aSopenharmony_ci{ 401cabdff1aSopenharmony_ci int x, y; 402cabdff1aSopenharmony_ci 403cabdff1aSopenharmony_ci /* This format is basically DXT5, with luma stored in alpha. 404cabdff1aSopenharmony_ci * Run a normal decompress and then reorder the components. */ 405cabdff1aSopenharmony_ci dxt5_block_internal(dst, stride, block); 406cabdff1aSopenharmony_ci 407cabdff1aSopenharmony_ci for (y = 0; y < 4; y++) 408cabdff1aSopenharmony_ci for (x = 0; x < 4; x++) 409cabdff1aSopenharmony_ci ycocg2rgba(dst + x * 4 + y * stride, 1); 410cabdff1aSopenharmony_ci 411cabdff1aSopenharmony_ci return 16; 412cabdff1aSopenharmony_ci} 413cabdff1aSopenharmony_ci 414cabdff1aSopenharmony_cistatic inline void rgtc_block_internal(uint8_t *dst, ptrdiff_t stride, 415cabdff1aSopenharmony_ci const uint8_t *block, 416cabdff1aSopenharmony_ci const int *color_tab, int mono, int offset, int pix_size) 417cabdff1aSopenharmony_ci{ 418cabdff1aSopenharmony_ci uint8_t indices[16]; 419cabdff1aSopenharmony_ci int x, y; 420cabdff1aSopenharmony_ci 421cabdff1aSopenharmony_ci decompress_indices(indices, block + 2); 422cabdff1aSopenharmony_ci 423cabdff1aSopenharmony_ci /* Only one or two channels are stored at most, since it only used to 424cabdff1aSopenharmony_ci * compress specular (black and white) or normal (red and green) maps. 425cabdff1aSopenharmony_ci * Although the standard says to zero out unused components, many 426cabdff1aSopenharmony_ci * implementations fill all of them with the same value. */ 427cabdff1aSopenharmony_ci for (y = 0; y < 4; y++) { 428cabdff1aSopenharmony_ci for (x = 0; x < 4; x++) { 429cabdff1aSopenharmony_ci int i = indices[x + y * 4]; 430cabdff1aSopenharmony_ci /* Interval expansion from [-1 1] or [0 1] to [0 255]. */ 431cabdff1aSopenharmony_ci int c = color_tab[i]; 432cabdff1aSopenharmony_ci 433cabdff1aSopenharmony_ci if (mono){ 434cabdff1aSopenharmony_ci dst [x * pix_size + y * stride + offset] = (uint8_t)c; 435cabdff1aSopenharmony_ci } 436cabdff1aSopenharmony_ci else{ 437cabdff1aSopenharmony_ci uint32_t pixel = RGBA(c, c, c, 255U); 438cabdff1aSopenharmony_ci AV_WL32(dst + x * pix_size + y * stride, pixel); 439cabdff1aSopenharmony_ci } 440cabdff1aSopenharmony_ci } 441cabdff1aSopenharmony_ci } 442cabdff1aSopenharmony_ci} 443cabdff1aSopenharmony_ci 444cabdff1aSopenharmony_cistatic inline void rgtc1_block_internal(uint8_t *dst, ptrdiff_t stride, 445cabdff1aSopenharmony_ci const uint8_t *block, int sign, int mono, int offset, int pix_size) 446cabdff1aSopenharmony_ci{ 447cabdff1aSopenharmony_ci int color_table[8]; 448cabdff1aSopenharmony_ci int r0, r1; 449cabdff1aSopenharmony_ci 450cabdff1aSopenharmony_ci if (sign) { 451cabdff1aSopenharmony_ci /* signed data is in [-128 127] so just offset it to unsigned 452cabdff1aSopenharmony_ci * and it can be treated exactly the same */ 453cabdff1aSopenharmony_ci r0 = ((int8_t) block[0]) + 128; 454cabdff1aSopenharmony_ci r1 = ((int8_t) block[1]) + 128; 455cabdff1aSopenharmony_ci } else { 456cabdff1aSopenharmony_ci r0 = block[0]; 457cabdff1aSopenharmony_ci r1 = block[1]; 458cabdff1aSopenharmony_ci } 459cabdff1aSopenharmony_ci 460cabdff1aSopenharmony_ci color_table[0] = r0; 461cabdff1aSopenharmony_ci color_table[1] = r1; 462cabdff1aSopenharmony_ci 463cabdff1aSopenharmony_ci if (r0 > r1) { 464cabdff1aSopenharmony_ci /* 6 interpolated color values */ 465cabdff1aSopenharmony_ci color_table[2] = (6 * r0 + 1 * r1) / 7; // bit code 010 466cabdff1aSopenharmony_ci color_table[3] = (5 * r0 + 2 * r1) / 7; // bit code 011 467cabdff1aSopenharmony_ci color_table[4] = (4 * r0 + 3 * r1) / 7; // bit code 100 468cabdff1aSopenharmony_ci color_table[5] = (3 * r0 + 4 * r1) / 7; // bit code 101 469cabdff1aSopenharmony_ci color_table[6] = (2 * r0 + 5 * r1) / 7; // bit code 110 470cabdff1aSopenharmony_ci color_table[7] = (1 * r0 + 6 * r1) / 7; // bit code 111 471cabdff1aSopenharmony_ci } else { 472cabdff1aSopenharmony_ci /* 4 interpolated color values */ 473cabdff1aSopenharmony_ci color_table[2] = (4 * r0 + 1 * r1) / 5; // bit code 010 474cabdff1aSopenharmony_ci color_table[3] = (3 * r0 + 2 * r1) / 5; // bit code 011 475cabdff1aSopenharmony_ci color_table[4] = (2 * r0 + 3 * r1) / 5; // bit code 100 476cabdff1aSopenharmony_ci color_table[5] = (1 * r0 + 4 * r1) / 5; // bit code 101 477cabdff1aSopenharmony_ci color_table[6] = 0; /* min range */ // bit code 110 478cabdff1aSopenharmony_ci color_table[7] = 255; /* max range */ // bit code 111 479cabdff1aSopenharmony_ci } 480cabdff1aSopenharmony_ci 481cabdff1aSopenharmony_ci rgtc_block_internal(dst, stride, block, color_table, mono, offset, pix_size); 482cabdff1aSopenharmony_ci} 483cabdff1aSopenharmony_ci 484cabdff1aSopenharmony_ci/** 485cabdff1aSopenharmony_ci * Decompress one block of a RGRC1 texture with signed components 486cabdff1aSopenharmony_ci * and store the resulting RGBA pixels in 'dst'. 487cabdff1aSopenharmony_ci * 488cabdff1aSopenharmony_ci * @param dst output buffer. 489cabdff1aSopenharmony_ci * @param stride scanline in bytes. 490cabdff1aSopenharmony_ci * @param block block to decompress. 491cabdff1aSopenharmony_ci * @return how much texture data has been consumed. 492cabdff1aSopenharmony_ci */ 493cabdff1aSopenharmony_cistatic int rgtc1s_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) 494cabdff1aSopenharmony_ci{ 495cabdff1aSopenharmony_ci rgtc1_block_internal(dst, stride, block, 1, 0, 0, 4); 496cabdff1aSopenharmony_ci 497cabdff1aSopenharmony_ci return 8; 498cabdff1aSopenharmony_ci} 499cabdff1aSopenharmony_ci 500cabdff1aSopenharmony_ci/** 501cabdff1aSopenharmony_ci * Decompress one block of a RGRC1 texture with unsigned components 502cabdff1aSopenharmony_ci * and store the resulting RGBA pixels in 'dst'. 503cabdff1aSopenharmony_ci * 504cabdff1aSopenharmony_ci * @param dst output buffer. 505cabdff1aSopenharmony_ci * @param stride scanline in bytes. 506cabdff1aSopenharmony_ci * @param block block to decompress. 507cabdff1aSopenharmony_ci * @return how much texture data has been consumed. 508cabdff1aSopenharmony_ci */ 509cabdff1aSopenharmony_cistatic int rgtc1u_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) 510cabdff1aSopenharmony_ci{ 511cabdff1aSopenharmony_ci rgtc1_block_internal(dst, stride, block, 0, 0, 0, 4); 512cabdff1aSopenharmony_ci 513cabdff1aSopenharmony_ci return 8; 514cabdff1aSopenharmony_ci} 515cabdff1aSopenharmony_ci 516cabdff1aSopenharmony_ci/** 517cabdff1aSopenharmony_ci * Decompress one block of a RGTC1 texture with unsigned components 518cabdff1aSopenharmony_ci * and overwrite the alpha component in 'dst' (RGBA data). 519cabdff1aSopenharmony_ci * 520cabdff1aSopenharmony_ci * @param dst output buffer. 521cabdff1aSopenharmony_ci * @param stride scanline in bytes. 522cabdff1aSopenharmony_ci * @param block block to decompress. 523cabdff1aSopenharmony_ci * @return how much texture data has been consumed. 524cabdff1aSopenharmony_ci */ 525cabdff1aSopenharmony_cistatic int rgtc1u_alpha_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) 526cabdff1aSopenharmony_ci{ 527cabdff1aSopenharmony_ci rgtc1_block_internal(dst, stride, block, 0, 1, 3, 4); 528cabdff1aSopenharmony_ci 529cabdff1aSopenharmony_ci return 8; 530cabdff1aSopenharmony_ci} 531cabdff1aSopenharmony_ci 532cabdff1aSopenharmony_ci/** 533cabdff1aSopenharmony_ci * Decompress one block of a RGTC1 texture with unsigned components 534cabdff1aSopenharmony_ci * to Gray 8. 535cabdff1aSopenharmony_ci * 536cabdff1aSopenharmony_ci * @param dst output buffer. 537cabdff1aSopenharmony_ci * @param stride scanline in bytes. 538cabdff1aSopenharmony_ci * @param block block to decompress. 539cabdff1aSopenharmony_ci * @return how much texture data has been consumed. 540cabdff1aSopenharmony_ci */ 541cabdff1aSopenharmony_cistatic int rgtc1u_gray_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) 542cabdff1aSopenharmony_ci{ 543cabdff1aSopenharmony_ci rgtc1_block_internal(dst, stride, block, 0, 1, 0, 1); 544cabdff1aSopenharmony_ci 545cabdff1aSopenharmony_ci return 8; 546cabdff1aSopenharmony_ci} 547cabdff1aSopenharmony_ci 548cabdff1aSopenharmony_cistatic inline void rgtc2_block_internal(uint8_t *dst, ptrdiff_t stride, 549cabdff1aSopenharmony_ci const uint8_t *block, int sign) 550cabdff1aSopenharmony_ci{ 551cabdff1aSopenharmony_ci /* 4x4 block containing 4 component pixels. */ 552cabdff1aSopenharmony_ci uint8_t c0[4 * 4 * 4]; 553cabdff1aSopenharmony_ci uint8_t c1[4 * 4 * 4]; 554cabdff1aSopenharmony_ci int x, y; 555cabdff1aSopenharmony_ci 556cabdff1aSopenharmony_ci /* Decompress the two channels separately and interleave them afterwards. */ 557cabdff1aSopenharmony_ci rgtc1_block_internal(c0, 16, block, sign, 0, 0, 4); 558cabdff1aSopenharmony_ci rgtc1_block_internal(c1, 16, block + 8, sign, 0, 0, 4); 559cabdff1aSopenharmony_ci 560cabdff1aSopenharmony_ci /* B is rebuilt exactly like a normal map. */ 561cabdff1aSopenharmony_ci for (y = 0; y < 4; y++) { 562cabdff1aSopenharmony_ci for (x = 0; x < 4; x++) { 563cabdff1aSopenharmony_ci uint8_t *p = dst + x * 4 + y * stride; 564cabdff1aSopenharmony_ci int r = c0[x * 4 + y * 16]; 565cabdff1aSopenharmony_ci int g = c1[x * 4 + y * 16]; 566cabdff1aSopenharmony_ci int b = 127; 567cabdff1aSopenharmony_ci 568cabdff1aSopenharmony_ci int d = (255 * 255 - r * r - g * g) / 2; 569cabdff1aSopenharmony_ci if (d > 0) 570cabdff1aSopenharmony_ci b = lrint(sqrtf(d)); 571cabdff1aSopenharmony_ci 572cabdff1aSopenharmony_ci p[0] = r; 573cabdff1aSopenharmony_ci p[1] = g; 574cabdff1aSopenharmony_ci p[2] = b; 575cabdff1aSopenharmony_ci p[3] = 255; 576cabdff1aSopenharmony_ci } 577cabdff1aSopenharmony_ci } 578cabdff1aSopenharmony_ci} 579cabdff1aSopenharmony_ci 580cabdff1aSopenharmony_ci/** 581cabdff1aSopenharmony_ci * Decompress one block of a RGRC2 texture with signed components 582cabdff1aSopenharmony_ci * and store the resulting RGBA pixels in 'dst'. Alpha is fully opaque. 583cabdff1aSopenharmony_ci * 584cabdff1aSopenharmony_ci * @param dst output buffer. 585cabdff1aSopenharmony_ci * @param stride scanline in bytes. 586cabdff1aSopenharmony_ci * @param block block to decompress. 587cabdff1aSopenharmony_ci * @return how much texture data has been consumed. 588cabdff1aSopenharmony_ci */ 589cabdff1aSopenharmony_cistatic int rgtc2s_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) 590cabdff1aSopenharmony_ci{ 591cabdff1aSopenharmony_ci rgtc2_block_internal(dst, stride, block, 1); 592cabdff1aSopenharmony_ci 593cabdff1aSopenharmony_ci return 16; 594cabdff1aSopenharmony_ci} 595cabdff1aSopenharmony_ci 596cabdff1aSopenharmony_ci/** 597cabdff1aSopenharmony_ci * Decompress one block of a RGRC2 texture with unsigned components 598cabdff1aSopenharmony_ci * and store the resulting RGBA pixels in 'dst'. Alpha is fully opaque. 599cabdff1aSopenharmony_ci * 600cabdff1aSopenharmony_ci * @param dst output buffer. 601cabdff1aSopenharmony_ci * @param stride scanline in bytes. 602cabdff1aSopenharmony_ci * @param block block to decompress. 603cabdff1aSopenharmony_ci * @return how much texture data has been consumed. 604cabdff1aSopenharmony_ci */ 605cabdff1aSopenharmony_cistatic int rgtc2u_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) 606cabdff1aSopenharmony_ci{ 607cabdff1aSopenharmony_ci rgtc2_block_internal(dst, stride, block, 0); 608cabdff1aSopenharmony_ci 609cabdff1aSopenharmony_ci return 16; 610cabdff1aSopenharmony_ci} 611cabdff1aSopenharmony_ci 612cabdff1aSopenharmony_ci/** 613cabdff1aSopenharmony_ci * Decompress one block of a 3Dc texture with unsigned components 614cabdff1aSopenharmony_ci * and store the resulting RGBA pixels in 'dst'. Alpha is fully opaque. 615cabdff1aSopenharmony_ci * 616cabdff1aSopenharmony_ci * @param dst output buffer. 617cabdff1aSopenharmony_ci * @param stride scanline in bytes. 618cabdff1aSopenharmony_ci * @param block block to decompress. 619cabdff1aSopenharmony_ci * @return how much texture data has been consumed. 620cabdff1aSopenharmony_ci */ 621cabdff1aSopenharmony_cistatic int dxn3dc_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) 622cabdff1aSopenharmony_ci{ 623cabdff1aSopenharmony_ci int x, y; 624cabdff1aSopenharmony_ci rgtc2_block_internal(dst, stride, block, 0); 625cabdff1aSopenharmony_ci 626cabdff1aSopenharmony_ci /* This is the 3Dc variant of RGTC2, with swapped R and G. */ 627cabdff1aSopenharmony_ci for (y = 0; y < 4; y++) { 628cabdff1aSopenharmony_ci for (x = 0; x < 4; x++) { 629cabdff1aSopenharmony_ci uint8_t *p = dst + x * 4 + y * stride; 630cabdff1aSopenharmony_ci FFSWAP(uint8_t, p[0], p[1]); 631cabdff1aSopenharmony_ci } 632cabdff1aSopenharmony_ci } 633cabdff1aSopenharmony_ci 634cabdff1aSopenharmony_ci return 16; 635cabdff1aSopenharmony_ci} 636cabdff1aSopenharmony_ci 637cabdff1aSopenharmony_ciav_cold void ff_texturedsp_init(TextureDSPContext *c) 638cabdff1aSopenharmony_ci{ 639cabdff1aSopenharmony_ci c->dxt1_block = dxt1_block; 640cabdff1aSopenharmony_ci c->dxt1a_block = dxt1a_block; 641cabdff1aSopenharmony_ci c->dxt2_block = dxt2_block; 642cabdff1aSopenharmony_ci c->dxt3_block = dxt3_block; 643cabdff1aSopenharmony_ci c->dxt4_block = dxt4_block; 644cabdff1aSopenharmony_ci c->dxt5_block = dxt5_block; 645cabdff1aSopenharmony_ci c->dxt5y_block = dxt5y_block; 646cabdff1aSopenharmony_ci c->dxt5ys_block = dxt5ys_block; 647cabdff1aSopenharmony_ci c->rgtc1s_block = rgtc1s_block; 648cabdff1aSopenharmony_ci c->rgtc1u_block = rgtc1u_block; 649cabdff1aSopenharmony_ci c->rgtc1u_gray_block = rgtc1u_gray_block; 650cabdff1aSopenharmony_ci c->rgtc1u_alpha_block = rgtc1u_alpha_block; 651cabdff1aSopenharmony_ci c->rgtc2s_block = rgtc2s_block; 652cabdff1aSopenharmony_ci c->rgtc2u_block = rgtc2u_block; 653cabdff1aSopenharmony_ci c->dxn3dc_block = dxn3dc_block; 654cabdff1aSopenharmony_ci} 655cabdff1aSopenharmony_ci 656cabdff1aSopenharmony_ci#define TEXTUREDSP_FUNC_NAME ff_texturedsp_decompress_thread 657cabdff1aSopenharmony_ci#define TEXTUREDSP_TEX_FUNC(a, b, c) tex_funct(a, b, c) 658cabdff1aSopenharmony_ci#include "texturedsp_template.c" 659