7#include <cuda_runtime_api.h>
12typedef unsigned int u32;
27 __device__
vec2(
float x,
float y) :
r(x),
g(y) {}
28 __device__
vec2(
float n = 0.0f) :
r(n),
g(n) {}
38 return *
this *
vec2(n);
41 return *
this + (o * -1.0f);
44 return *
this * (1.0f / n);
57 __device__
vec3(
float x,
float y,
float z) :
vec2(x, y),
b(z) {}
68 return *
this *
vec3(n);
71 return *
this + (o * -1.0f);
74 return *
this * (1.0f / n);
107 return a.
r * b.
r + a.
g * b.
g + a.
b * b.
b;
114__device__
static float clamp(
const float & v,
float min_val,
float max_val) {
115 return min(max_val,
max(min_val, v));
119 return vec2(fabsf(v.
r), fabsf(v.
g));
123 return vec3(roundf(v.
r), roundf(v.
g), roundf(v.
b));
127 return a * (1.0f - q) + b * q;
139__device__
static const float offset = 128.0 / 255.0;
143 float Y = (color.
r + 2.0 * color.
g + color.
b) * 0.25;
144 float Co = ( ( 2.0 * color.
r - 2.0 * color.
b ) * 0.25 +
offset );
145 float Cg = ( ( -color.
r + 2.0 * color.
g - color.
b) * 0.25 +
offset );
147 return vec3(Y, Co, Cg);
156 return dot(c0-c1, c0-c1);
164 for (
int i = 1; i < 16; i++ ) {
165 mincol =
min(mincol, block[i]);
166 maxcol =
max(maxcol, block[i]);
176__device__
static void InsetYBBox(
float & mincol,
float & maxcol)
178 float inset = (maxcol - mincol) / 32.0 - (16.0 / 255.0) / 32.0;
179 mincol =
clamp(mincol + inset, 0.0, 1.0);
180 maxcol =
clamp(maxcol - inset, 0.0, 1.0);
184 vec2 inset = (maxcol - mincol) / 16.0 - (8.0 / 255.0) / 16.0;
185 mincol =
clamp(mincol + inset, 0.0, 1.0);
186 maxcol =
clamp(maxcol - inset, 0.0, 1.0);
246 float m =
max(
max(m0.
r, m0.
g), max(m1.
r, m1.
g));
248 const float s0 = 64.0 / 255.0;
249 const float s1 = 32.0 / 255.0;
262 vec2 mid = (maxColor + minColor) * 0.5;
265 for (
int i = 0; i < 16; i++ ) {
266 vec2 t = block[i].
gb() - mid;
273 float & maxcol_r,
float & maxcol_g,
276 vec2 mincol =
vec2(mincol_r, mincol_g);
277 vec2 maxcol =
vec2(maxcol_r, maxcol_g);
279 maxcol = (maxcol -
offset) *
float(scale) + float(
offset);
280 mincol = (mincol -
offset) *
float(scale) + float(
offset);
291 outp.
r = (imaxcol.
r << 11u) | (imaxcol.
g << 5u) | (scale -
UINT(1));
292 outp.
g = (imincol.
r << 11u) | (imincol.
g << 5u) | (scale -
UINT(1));
294 imaxcol.
r = (imaxcol.
r << 3u) | (imaxcol.
r >> 2u);
295 imaxcol.
g = (imaxcol.
g << 2u) | (imaxcol.
g >> 4u);
296 imincol.
r = (imincol.
r << 3u) | (imincol.
r >> 2u);
297 imincol.
g = (imincol.
g << 2u) | (imincol.
g >> 4u);
299 maxcol =
vec2(imaxcol) * (1.0 / 255.0);
300 mincol =
vec2(imincol) * (1.0 / 255.0);
303 maxcol = (maxcol -
offset) /
float(scale) + float(
offset);
304 mincol = (mincol -
offset) /
float(scale) + float(
offset);
312 return outp.
r | (outp.
g << 16u);
321 c[2] =
lerp(c[0], c[1], 1.0/3.0);
322 c[3] =
lerp(c[0], c[1], 2.0/3.0);
326 for (
int i = 0; i < 16; i++ )
336 b.x = dist.x > dist.w ? 1u : 0u;
337 b.y = dist.y > dist.z ? 1u : 0u;
338 b.z = dist.x > dist.z ? 1u : 0u;
339 b.w = dist.y > dist.w ? 1u : 0u;
340 UINT b4 = dist.z > dist.w ? 1u : 0u;
342 UINT index = (b.x & b4) | (((b.y & b.z) | (b.x & b.w)) << 1u);
343 indices |= index << (
UINT(i) * 2u);
352 uvec2 tmp =
uvec2(roundf(mincol * 255.0), roundf(maxcol * 255.0));
356 return (c0 << 8u) | c1;
362 const float ALPHA_RANGE = 7.0;
364 float mid = (maxAlpha - minAlpha) / (2.0 * ALPHA_RANGE);
366 float ab1 = minAlpha + mid;
367 float ab2 = (6.0 * maxAlpha + 1.0 * minAlpha) * (1.0 / ALPHA_RANGE) + mid;
368 float ab3 = (5.0 * maxAlpha + 2.0 * minAlpha) * (1.0 / ALPHA_RANGE) + mid;
369 float ab4 = (4.0 * maxAlpha + 3.0 * minAlpha) * (1.0 / ALPHA_RANGE) + mid;
370 float ab5 = (3.0 * maxAlpha + 4.0 * minAlpha) * (1.0 / ALPHA_RANGE) + mid;
371 float ab6 = (2.0 * maxAlpha + 5.0 * minAlpha) * (1.0 / ALPHA_RANGE) + mid;
372 float ab7 = (1.0 * maxAlpha + 6.0 * minAlpha) * (1.0 / ALPHA_RANGE) + mid;
377 for (
int i = 0; i < 6; i++ ) {
378 float a = block[i].
r;
380 index += (a <= ab1) ? 1u : 0u;
381 index += (a <= ab2) ? 1u : 0u;
382 index += (a <= ab3) ? 1u : 0u;
383 index += (a <= ab4) ? 1u : 0u;
384 index += (a <= ab5) ? 1u : 0u;
385 index += (a <= ab6) ? 1u : 0u;
386 index += (a <= ab7) ? 1u : 0u;
388 index ^= (2u > index) ? 1u : 0u;
389 indices.
r |= index << (3u *
UINT(i) + 16u);
392 indices.
g = index >> 1u;
394 for (
int i = 6; i < 16; i++ ) {
395 float a = block[i].
r;
397 index += (a <= ab1) ? 1u : 0u;
398 index += (a <= ab2) ? 1u : 0u;
399 index += (a <= ab3) ? 1u : 0u;
400 index += (a <= ab4) ? 1u : 0u;
401 index += (a <= ab5) ? 1u : 0u;
402 index += (a <= ab6) ? 1u : 0u;
403 index += (a <= ab7) ? 1u : 0u;
405 index ^= (2u > index) ? 1u : 0u;
406 indices.
g |= index << (3u *
UINT(i) - 16u);
426 r = rintf(__saturatef(r) * 31.0f);
427 g = rintf(__saturatef(g) * 63.0f);
428 b = rintf(__saturatef(b) * 31.0f);
431 const u32 code = ((
u32)r << 11) + ((
u32)g << 5) + (
u32)b;
434 r *= 0.0322580645161f;
435 g *= 0.015873015873f;
436 b *= 0.0322580645161f;
444__device__
static void yuv_to_rgb(
float & r,
float & g,
float & b) {
445 const float y = 1.1643f * (r - 0.0625f);
446 const float u = g - 0.5f;
447 const float v = b - 0.5f;
449 g = y - 0.2132f * u - 0.5328f * v;
456__device__
static void swap(T & a, T & b) {
464template <
int DXT_TYPE>
466 float r[16],
float g[16],
float b[16]);
473 float r[16],
float g[16],
float b[16]) {
477 for(
int i = 0; i < 16; i++) {
486 float tmp = maxcol.
b;
507 ((uint4*)out)[block_idx] = outp;
514 float r[16],
float g[16],
float b[16]) {
516 float mincol_r = r[0];
517 float mincol_g = g[0];
518 float mincol_b = b[0];
519 float maxcol_r = r[0];
520 float maxcol_g = g[0];
521 float maxcol_b = b[0];
522 for(
int i = 1; i < 16; i++) {
523 mincol_r =
min(mincol_r, r[i]);
524 mincol_g =
min(mincol_g, g[i]);
525 mincol_b =
min(mincol_b, b[i]);
526 maxcol_r =
max(maxcol_r, r[i]);
527 maxcol_g =
max(maxcol_g, g[i]);
528 maxcol_b =
max(maxcol_b, b[i]);
532 const float inset_r = (maxcol_r - mincol_r) * 0.0625f;
533 const float inset_g = (maxcol_g - mincol_g) * 0.0625f;
534 const float inset_b = (maxcol_b - mincol_b) * 0.0625f;
543 const float center_r = (mincol_r + maxcol_r) * 0.5f;
544 const float center_g = (mincol_g + maxcol_g) * 0.5f;
545 const float center_b = (mincol_b + maxcol_b) * 0.5f;
548 for(
int i = 0; i < 16; i++) {
549 const float dir_r = r[i] - center_r;
550 const float dir_g = g[i] - center_g;
551 const float dir_b = b[i] - center_b;
552 cov_x += dir_r * dir_b;
553 cov_y += dir_g * dir_b;
556 swap(maxcol_r, mincol_r);
559 swap(maxcol_g, mincol_g);
568 const bool swap_end_colors = max_code < min_code;
571 const u32 palette_code = swap_end_colors ?
572 min_code + (max_code << 16): max_code + (min_code << 16);
576 if(max_code != min_code) {
580 const float dir_r = mincol_r - maxcol_r;
581 const float dir_g = mincol_g - maxcol_g;
582 const float dir_b = mincol_b - maxcol_b;
583 const float dir_sqr_len = dir_r * dir_r + dir_g * dir_g + dir_b * dir_b;
584 const float dir_inv_sqr_len = __fdividef(1.0f, dir_sqr_len);
585 const float t_r = dir_r * dir_inv_sqr_len;
586 const float t_g = dir_g * dir_inv_sqr_len;
587 const float t_b = dir_b * dir_inv_sqr_len;
588 const float t_bias = t_r * maxcol_r + t_g * maxcol_g + t_b * maxcol_b;
591 for(
int i = 0; i < 16; i++) {
593 const float col_t = r[i] * t_r + g[i] * t_g + b[i] * t_b - t_bias;
597 const u32 col_idx = (
u32)(3.0f * __saturatef(col_t) + 0.5f);
600 indices += col_idx << (i * 2);
605 if(swap_end_colors) {
611 const u32 lsbs = indices & 0x55555555;
612 const u32 msbs = indices & 0xaaaaaaaa;
613 indices = msbs ^ (2 * lsbs + (msbs >> 1));
616 ((uint2*)out)[block_idx] = make_uint2(palette_code, indices);
622template <
bool YUV_TO_RGB,
bool VERTICAL_MIRRORING,
int DXT_TYPE>
623__global__
static void dxt_kernel(
const void * src,
void * out,
int size_x,
int size_y) {
625 const int block_idx_x = threadIdx.x + blockIdx.x * blockDim.x;
626 const int block_idx_y = threadIdx.y + blockIdx.y * blockDim.y;
629 const int block_x = block_idx_x * 4;
630 const int block_y = block_idx_y * 4;
633 const int block_idx = block_idx_x + (size_x >> 2) * block_idx_y;
636 if(block_y >= size_y || block_x >= size_x) {
646 const int src_stride = (size_x >> 2) * 3;
647 for(
int y = 0; y < 4; y++) {
649 const int load_offset = y * 4;
652 int row_idx = block_y + y;
653 if(VERTICAL_MIRRORING) {
654 row_idx = size_y - 1 - row_idx;
656 const uchar4 *
const row_src = (uchar4*)src
657 + src_stride * row_idx
661 const uchar4 p0 = row_src[0];
662 const uchar4 p1 = row_src[1];
663 const uchar4 p2 = row_src[2];
666 r[load_offset + 0] = p0.x * 0.00392156862745f;
667 g[load_offset + 0] = p0.y * 0.00392156862745f;
668 b[load_offset + 0] = p0.z * 0.00392156862745f;
671 r[load_offset + 1] = p0.w * 0.00392156862745f;
672 g[load_offset + 1] = p1.x * 0.00392156862745f;
673 b[load_offset + 1] = p1.y * 0.00392156862745f;
676 r[load_offset + 2] = p1.z * 0.00392156862745f;
677 g[load_offset + 2] = p1.w * 0.00392156862745f;
678 b[load_offset + 2] = p2.x * 0.00392156862745f;
681 r[load_offset + 3] = p2.y * 0.00392156862745f;
682 g[load_offset + 3] = p2.z * 0.00392156862745f;
683 b[load_offset + 3] = p2.w * 0.00392156862745f;
688 for(
int i = 0; i < 16; i++) {
699 const int block_idx_x = threadIdx.x + blockIdx.x * blockDim.x;
702 if(block_idx_x >= pix_count / 2) {
706 uchar4 *this_src = ((uchar4 *) src) + block_idx_x * 2;
707 uchar4 *this_out = ((uchar4 *) out) + block_idx_x * 3;
709 uchar4 pix12 = this_src[0];
710 uchar4 pix34 = this_src[1];
713 out_pix[0].x = pix12.y;
714 out_pix[0].y = pix12.x;
715 out_pix[0].z = pix12.z;
717 out_pix[0].w = pix12.w;
718 out_pix[1].x = pix12.x;
719 out_pix[1].y = pix12.z;
721 out_pix[1].z = pix34.y;
722 out_pix[1].w = pix34.x;
723 out_pix[2].x = pix34.z;
725 out_pix[2].y = pix34.w;
726 out_pix[2].z = pix34.x;
727 out_pix[2].w = pix34.z;
729 this_out[0] = out_pix[0];
730 this_out[1] = out_pix[1];
731 this_out[2] = out_pix[2];
735template <
bool YUV_TO_RGB,
int DXT_TYPE>
736static int dxt_launch(
const void * src,
void * out,
int sx,
int sy, cudaStream_t str) {
738 bool mirrored =
false;
745 if((sx & 3) || (sy & 3) || (15 & (
size_t)src) || (7 & (
size_t)out)) {
750 const dim3 tsiz(16, 16);
751 const dim3 gsiz((sx + tsiz.x - 1) / tsiz.x, (sy + tsiz.y - 1) / tsiz.y);
759 return cudaSuccess != cudaStreamSynchronize(str) ? -3 : 0;
765 const dim3 tsiz(64, 1);
766 int thread_count = pix_count / 4;
767 const dim3 gsiz((thread_count + tsiz.x - 1) / tsiz.x, 1);
769 return cudaSuccess != cudaStreamSynchronize((cudaStream_t) str) ? -3 : 0;
static __device__ void InsetYBBox(float &mincol, float &maxcol)
static __device__ uvec2 EmitAlphaIndicesYCoCgDXT5(vec3 block[16], float minAlpha, float maxAlpha)
static __device__ vec3 ConvertRGBToYCoCg(vec3 color)
static __device__ vec3 lerp(const vec3 &a, const vec3 &b, const float q)
__device__ void dxt_encode(void *out, const int block_idx, float r[16], float g[16], float b[16])
Encodes and saves the block.
static __device__ void swap(T &a, T &b)
Swaps two referenced values.
static int dxt_launch(const void *src, void *out, int sx, int sy, cudaStream_t str)
Compute grid size and launch DXT kernel.
static __device__ void InsetCoCgBBox(vec2 &mincol, vec2 &maxcol)
static __device__ float colorDistance(vec2 c0, vec2 c1)
static __device__ void FindMinMaxColorsBox(vec3 block[16], vec3 &mincol, vec3 &maxcol)
static __device__ float dot(const vec3 &a, const vec3 &b)
__device__ void dxt_encode< 6 >(void *out, const int block_idx, float r[16], float g[16], float b[16])
static __device__ UINT EmitEndPointsYCoCgDXT5(float &mincol_r, float &mincol_g, float &maxcol_r, float &maxcol_g, UINT scale)
static __device__ u32 encode_endpoint(float &r, float &g, float &b)
Encodes color palette endpoint into 565 code and adjusts input values.
static __device__ bool SelectYCoCgDiagonal(const vec3 block[16], vec2 minColor, vec2 maxColor)
static __device__ vec2 abs(const vec2 &v)
int cuda_yuv_to_dxt1(const void *src, void *out, int size_x, int size_y, cuda_wrapper_stream_t stream)
int cuda_yuv_to_dxt6(const void *src, void *out, int size_x, int size_y, cuda_wrapper_stream_t stream)
static __device__ void yuv_to_rgb(float &r, float &g, float &b)
Transform YUV to RGB.
static __device__ UINT ScaleYCoCg(vec2 minColor, vec2 maxColor)
int cuda_rgb_to_dxt6(const void *src, void *out, int size_x, int size_y, cuda_wrapper_stream_t stream)
static __device__ UINT EmitIndicesYCoCgDXT5(vec3 block[16], vec2 mincol, vec2 maxcol)
__device__ void dxt_encode< 1 >(void *out, const int block_idx, float r[16], float g[16], float b[16])
Encodes the block into DXT1 format and saves it into output buffer.
int cuda_rgb_to_dxt1(const void *src, void *out, int size_x, int size_y, cuda_wrapper_stream_t stream)
static __global__ void dxt_kernel(const void *src, void *out, int size_x, int size_y)
static __device__ vec2 clamp(const vec2 &v, float min_val, float max_val)
static __device__ vec3 round(const vec3 &v)
int cuda_yuv422_to_yuv444(const void *src, void *out, int pix_count, cuda_wrapper_stream_t str)
static __device__ UINT EmitAlphaEndPointsYCoCgDXT5(float mincol, float maxcol)
static __global__ void yuv422_to_yuv444_kernel(const void *src, void *out, int pix_count)
static __device__ const float offset
Interface of DXT compression CUDA implementation.
void * cuda_wrapper_stream_t
__device__ uvec2(u32 x, u32 y)
__device__ uvec2(u32 n=0)
__device__ uvec3(u32 r, u32 g, u32 b)
__device__ uvec3(u32 n=0)
__device__ vec2(float x, float y)
__device__ vec2 operator+(const vec2 &o) const
__device__ vec2 operator*(const vec2 &v) const
__device__ vec2 operator*(const float n) const
__device__ vec2 operator/(const float n) const
__device__ vec2(float n=0.0f)
__device__ vec2 operator-(const vec2 &o) const
__device__ vec3 operator/(const float n) const
__device__ vec3 operator-(const vec3 &o) const
__device__ vec3 operator*(const float n) const
__device__ vec2 gb() const
__device__ vec3 operator*(const vec3 &v) const
__device__ vec3(const uvec3 &v)
__device__ vec3(float n=0.0f)
__device__ vec3 operator+(const vec3 &o) const
__device__ vec3(float x, float y, float z)
__device__ vec3(const vec2 &v)