UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
cuda_dxt.cu
Go to the documentation of this file.
1
6
7#include <cuda_runtime_api.h>
8#include <stdio.h>
9#include "cuda_dxt.h"
10
11
12typedef unsigned int u32;
13typedef u32 UINT;
14
15struct vec3;
16struct uvec2;
17
18struct uvec3 {
19 u32 r, g, b;
20 __device__ uvec3(u32 r, u32 g, u32 b) : r(r), g(g), b(b) {}
21 __device__ uvec3(u32 n = 0) : r(n), g(n), b(n) {}
22 __device__ uvec3(const vec3 & v);
23};
24
25struct vec2 {
26 float r, g;
27 __device__ vec2(float x, float y) : r(x), g(y) {}
28 __device__ vec2(float n = 0.0f) : r(n), g(n) {}
29 __device__ vec2(const vec3 & v);
30 __device__ vec2(const uvec2 & v);
31 __device__ vec2 operator+(const vec2 & o) const {
32 return vec2(r + o.r, g + o.g);
33 }
34 __device__ vec2 operator*(const vec2 & v) const {
35 return vec2(r * v.r, g * v.g);
36 }
37 __device__ vec2 operator*(const float n) const {
38 return *this * vec2(n);
39 }
40 __device__ vec2 operator-(const vec2 & o) const {
41 return *this + (o * -1.0f);
42 }
43 __device__ vec2 operator/(const float n) const {
44 return *this * (1.0f / n);
45 }
46};
47
48struct uvec2 {
50 __device__ uvec2(u32 x, u32 y) : r(x), g(y) {}
51 __device__ uvec2(u32 n = 0) : r(n), g(n) {}
52 __device__ uvec2(const vec2 & v);
53};
54
55struct vec3 : public vec2 {
56 float b;
57 __device__ vec3(float x, float y, float z) : vec2(x, y), b(z) {}
58 __device__ vec3(float n = 0.0f) : vec2(n), b(n) {}
59 __device__ vec3(const vec2 & v) : vec2(v), b(0.0f) {}
60 __device__ vec3(const uvec3 & v) : vec2(v.r, v.g), b(v.b) {}
61 __device__ vec3 operator+(const vec3 & o) const {
62 return vec3(r + o.r, g + o.g, b + o.b);
63 }
64 __device__ vec3 operator*(const vec3 & v) const {
65 return vec3(r * v.r, g * v.g, b * v.b);
66 }
67 __device__ vec3 operator*(const float n) const {
68 return *this * vec3(n);
69 }
70 __device__ vec3 operator-(const vec3 & o) const {
71 return *this + (o * -1.0f);
72 }
73 __device__ vec3 operator/(const float n) const {
74 return *this * (1.0f / n);
75 }
76// __device__ vec2 & yz() {
77// return *this;
78// }
79 __device__ vec2 gb() const {
80 return vec2(g, b);
81 }
82};
83
84__device__ uvec3::uvec3(const vec3 & v) : r(v.r), g(v.g), b(v.b) {}
85__device__ uvec2::uvec2(const vec2 & v) : r(v.r), g(v.g) {}
86__device__ vec2::vec2(const vec3 & v) : r(v.r), g(v.g) {}
87__device__ vec2::vec2(const uvec2 & v) : r(v.r), g(v.g) {}
88
89
90__device__ static vec3 min(const vec3 & a, const vec3 & b) {
91 return vec3(min(a.r, b.r), min(a.g, b.g), min(a.b, b.b));
92}
93
94__device__ static vec3 max(const vec3 & a, const vec3 & b) {
95 return vec3(max(a.r, b.r), max(a.g, b.g), max(a.b, b.b));
96}
97
98__device__ static vec2 min(const vec2 & a, const vec2 & b) {
99 return vec2(min(a.r, b.r), min(a.g, b.g));
100}
101
102__device__ static vec2 max(const vec2 & a, const vec2 & b) {
103 return vec2(max(a.r, b.r), max(a.g, b.g));
104}
105
106__device__ static float dot(const vec3 & a, const vec3 & b) {
107 return a.r * b.r + a.g * b.g + a.b * b.b;
108}
109
110__device__ static vec2 clamp(const vec2 & v, float min_val, float max_val) {
111 return min(vec2(max_val), max(vec2(min_val), v));
112}
113
114__device__ static float clamp(const float & v, float min_val, float max_val) {
115 return min(max_val, max(min_val, v));
116}
117
118__device__ static vec2 abs(const vec2 & v) {
119 return vec2(fabsf(v.r), fabsf(v.g));
120}
121
122__device__ static vec3 round(const vec3 & v) {
123 return vec3(roundf(v.r), roundf(v.g), roundf(v.b));
124}
125
126__device__ static vec3 lerp(const vec3 & a, const vec3 & b, const float q) {
127 return a * (1.0f - q) + b * q;
128}
129
130
131
137
138
139__device__ static const float offset = 128.0 / 255.0;
140
141__device__ static vec3 ConvertRGBToYCoCg(vec3 color)
142{
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 );
146
147 return vec3(Y, Co, Cg);
148}
149
150// __device__ static float colorDistance(vec3 c0, vec3 c1)
151// {
152// return dot(c0-c1, c0-c1);
153// }
154__device__ static float colorDistance(vec2 c0, vec2 c1)
155{
156 return dot(c0-c1, c0-c1);
157}
158
159__device__ static void FindMinMaxColorsBox(vec3 block[16], vec3 & mincol, vec3 & maxcol)
160{
161 mincol = block[0];
162 maxcol = block[0];
163
164 for ( int i = 1; i < 16; i++ ) {
165 mincol = min(mincol, block[i]);
166 maxcol = max(maxcol, block[i]);
167 }
168}
169
170// __device__ static void InsetBBox(vec3 & mincol, vec3 & maxcol)
171// {
172// vec3 inset = (maxcol - mincol) / 16.0 - (8.0 / 255.0) / 16.0;
173// mincol = clamp(mincol + inset, 0.0, 1.0);
174// maxcol = clamp(maxcol - inset, 0.0, 1.0);
175// }
176__device__ static void InsetYBBox(float & mincol, float & maxcol)
177{
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);
181}
182__device__ static void InsetCoCgBBox(vec2 & mincol, vec2 & maxcol)
183{
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);
187}
188
189// __device__ static void SelectDiagonal(vec3 block[16], vec3 & mincol, vec3 & maxcol)
190// {
191// vec3 center = (mincol + maxcol) * 0.5;
192//
193// vec2 cov = vec2(0, 0);
194// for (int i = 0; i < 16; i++) {
195// vec3 t = block[i] - center;
196// cov.r += t.r * t.b;
197// cov.g += t.g * t.b;
198// }
199//
200// if (cov.r < 0.0) {
201// float temp = maxcol.r;
202// maxcol.r = mincol.r;
203// mincol.r = temp;
204// }
205// if (cov.g < 0.0) {
206// float temp = maxcol.g;
207// maxcol.g = mincol.g;
208// mincol.g = temp;
209// }
210// }
211
212// __device__ static vec3 RoundAndExpand(vec3 v, UINT & w)
213// {
214// uvec3 c = uvec3(round(v * vec3(31, 63, 31)));
215// w = (c.r << 11u) | (c.g << 5u) | c.b;
216//
217// c.r = (c.r << 3u) | (c.r >> 2u);
218// c.b = (c.b << 3u) | (c.b >> 2u);
219// c.g = (c.g << 2u) | (c.g >> 4u);
220//
221// return vec3(c) * (1.0 / 255.0);
222// }
223
224// __device__ static UINT EmitEndPointsDXT1(vec3 & mincol, vec3 & maxcol)
225// {
226// uvec2 outp;
227// maxcol = RoundAndExpand(maxcol, outp.r);
228// mincol = RoundAndExpand(mincol, outp.g);
229//
230// // We have to do this in case we select an alternate diagonal.
231// if (outp.r < outp.g) {
232// vec3 tmp = mincol;
233// mincol = maxcol;
234// maxcol = tmp;
235// return outp.g | (outp.r << 16u);
236// }
237//
238// return outp.r | (outp.g << 16u);
239// }
240
241__device__ static UINT ScaleYCoCg(vec2 minColor, vec2 maxColor)
242{
243 vec2 m0 = abs(minColor - offset);
244 vec2 m1 = abs(maxColor - offset);
245
246 float m = max(max(m0.r, m0.g), max(m1.r, m1.g));
247
248 const float s0 = 64.0 / 255.0;
249 const float s1 = 32.0 / 255.0;
250
251 UINT scale = 1u;
252 if ( m < s0 )
253 scale = 2u;
254 if ( m < s1 )
255 scale = 4u;
256
257 return scale;
258}
259
260__device__ static bool SelectYCoCgDiagonal(const vec3 block[16], vec2 minColor, vec2 maxColor)
261{
262 vec2 mid = (maxColor + minColor) * 0.5;
263
264 float cov = 0.0;
265 for ( int i = 0; i < 16; i++ ) {
266 vec2 t = block[i].gb() - mid;
267 cov += t.r * t.g;
268 }
269 return cov < 0.0;
270}
271
272__device__ static UINT EmitEndPointsYCoCgDXT5(float & mincol_r, float & mincol_g,
273 float & maxcol_r, float & maxcol_g,
274 UINT scale)
275{
276 vec2 mincol = vec2(mincol_r, mincol_g);
277 vec2 maxcol = vec2(maxcol_r, maxcol_g);
278
279 maxcol = (maxcol - offset) * float(scale) + float(offset);
280 mincol = (mincol - offset) * float(scale) + float(offset);
281
282 InsetCoCgBBox(mincol, maxcol);
283
284 maxcol = round(maxcol * vec2(31, 63));
285 mincol = round(mincol * vec2(31, 63));
286
287 uvec2 imaxcol = uvec2(maxcol);
288 uvec2 imincol = uvec2(mincol);
289
290 uvec2 outp;
291 outp.r = (imaxcol.r << 11u) | (imaxcol.g << 5u) | (scale - UINT(1));
292 outp.g = (imincol.r << 11u) | (imincol.g << 5u) | (scale - UINT(1));
293
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);
298
299 maxcol = vec2(imaxcol) * (1.0 / 255.0);
300 mincol = vec2(imincol) * (1.0 / 255.0);
301
302 // Undo rescale.
303 maxcol = (maxcol - offset) / float(scale) + float(offset);
304 mincol = (mincol - offset) / float(scale) + float(offset);
305
306 // distribute back
307 mincol_r = mincol.r;
308 mincol_g = mincol.g;
309 maxcol_r = maxcol.r;
310 maxcol_g = maxcol.g;
311
312 return outp.r | (outp.g << 16u);
313}
314
315__device__ static UINT EmitIndicesYCoCgDXT5(vec3 block[16], vec2 mincol, vec2 maxcol)
316{
317 // Compute palette
318 vec2 c[4];
319 c[0] = maxcol;
320 c[1] = mincol;
321 c[2] = lerp(c[0], c[1], 1.0/3.0);
322 c[3] = lerp(c[0], c[1], 2.0/3.0);
323
324 // Compute indices
325 UINT indices = 0u;
326 for ( int i = 0; i < 16; i++ )
327 {
328 // find index of closest color
329 float4 dist;
330 dist.x = colorDistance(block[i].gb(), c[0]);
331 dist.y = colorDistance(block[i].gb(), c[1]);
332 dist.z = colorDistance(block[i].gb(), c[2]);
333 dist.w = colorDistance(block[i].gb(), c[3]);
334
335 uint4 b;
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;
341
342 UINT index = (b.x & b4) | (((b.y & b.z) | (b.x & b.w)) << 1u);
343 indices |= index << (UINT(i) * 2u);
344 }
345
346 // Output indices
347 return indices;
348}
349
350__device__ static UINT EmitAlphaEndPointsYCoCgDXT5(float mincol, float maxcol)
351{
352 uvec2 tmp = uvec2(roundf(mincol * 255.0), roundf(maxcol * 255.0));
353 UINT c0 = tmp.r;
354 UINT c1 = tmp.g;
355
356 return (c0 << 8u) | c1;
357}
358
359// Version shown in the YCoCg-DXT article.
360__device__ static uvec2 EmitAlphaIndicesYCoCgDXT5(vec3 block[16], float minAlpha, float maxAlpha)
361{
362 const float ALPHA_RANGE = 7.0;
363
364 float mid = (maxAlpha - minAlpha) / (2.0 * ALPHA_RANGE);
365
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;
373
374 uvec2 indices = uvec2(0, 0);
375
376 UINT index = 1u;
377 for ( int i = 0; i < 6; i++ ) {
378 float a = block[i].r;
379 index = 1u;
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;
387 index &= 7u;
388 index ^= (2u > index) ? 1u : 0u;
389 indices.r |= index << (3u * UINT(i) + 16u);
390 }
391
392 indices.g = index >> 1u;
393
394 for ( int i = 6; i < 16; i++ ) {
395 float a = block[i].r;
396 index = 1u;
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;
404 index &= 7u;
405 index ^= (2u > index) ? 1u : 0u;
406 indices.g |= index << (3u * UINT(i) - 16u);
407 }
408
409 return indices;
410}
411
412
413
419
420
421
422
424__device__ static u32 encode_endpoint(float & r, float & g, float & b) {
425 // clamp to range [0,1] and use full output range for each component
426 r = rintf(__saturatef(r) * 31.0f);
427 g = rintf(__saturatef(g) * 63.0f); // 6 bits for green sample
428 b = rintf(__saturatef(b) * 31.0f);
429
430 // compose output 16bit code representing the endpoint color
431 const u32 code = ((u32)r << 11) + ((u32)g << 5) + (u32)b;
432
433 // convert all 3 endpoint component samples back to unit range
434 r *= 0.0322580645161f; // divide by 31
435 g *= 0.015873015873f; // divide by 63
436 b *= 0.0322580645161f; // divide by 31
437
438 // return output 16bit code for the endpoint
439 return code;
440}
441
442
444__device__ static void yuv_to_rgb(float & r, float & g, float & b) {
445 const float y = 1.1643f * (r - 0.0625f); // TODO: convert to FFMA
446 const float u = g - 0.5f;
447 const float v = b - 0.5f;
448 r = y + 1.7926f * v;
449 g = y - 0.2132f * u - 0.5328f * v;
450 b = y + 2.1124f * u;
451}
452
453
455template <typename T>
456__device__ static void swap(T & a, T & b) {
457 const T temp = a;
458 a = b;
459 b = temp;
460}
461
462
464template <int DXT_TYPE>
465__device__ void dxt_encode(void * out, const int block_idx,
466 float r[16], float g[16], float b[16]);
467
468
471template <>
472__device__ void dxt_encode<6>(void * out, const int block_idx,
473 float r[16], float g[16], float b[16]) {
474 // Read block of data
475 vec3 block[16];
476
477 for(int i = 0; i < 16; i++) {
478 block[i] = ConvertRGBToYCoCg(vec3(r[i], g[i], b[i]));
479 }
480
481 // Find min and max colors
482 vec3 mincol, maxcol;
483 FindMinMaxColorsBox(block, mincol, maxcol);
484
485 if(SelectYCoCgDiagonal(block, mincol.gb(), maxcol.gb())) {
486 float tmp = maxcol.b;
487 maxcol.b = mincol.b;
488 mincol.b = tmp;
489 }
490
491 u32 scale = ScaleYCoCg(mincol.gb(), maxcol.gb());
492// printf("Scale: %u.\n", scale);
493 // Output CoCg in DXT1 block.
494 uint4 outp;
495 outp.z = EmitEndPointsYCoCgDXT5(mincol.g, mincol.b, maxcol.g, maxcol.b, scale);
496 outp.w = EmitIndicesYCoCgDXT5(block, mincol.gb(), maxcol.gb());
497
498 InsetYBBox(mincol.r, maxcol.r);
499
500 // Output Y in DXT5 alpha block.
501 outp.x = EmitAlphaEndPointsYCoCgDXT5(mincol.r, maxcol.r);
502
503 uvec2 indices = EmitAlphaIndicesYCoCgDXT5(block, mincol.r, maxcol.r);
504 outp.x |= indices.r;
505 outp.y = indices.g;
506
507 ((uint4*)out)[block_idx] = outp;
508
509}
510
512template <>
513__device__ void dxt_encode<1>(void * out, const int block_idx,
514 float r[16], float g[16], float b[16]) {
515 // find min and max sample values for each component
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]);
529 }
530
531 // inset the bounding box
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;
535 mincol_r += inset_r;
536 mincol_g += inset_g;
537 mincol_b += inset_b;
538 maxcol_r -= inset_r;
539 maxcol_g -= inset_g;
540 maxcol_b -= inset_b;
541
542 // select diagonal
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;
546 float cov_x = 0.0f;
547 float cov_y = 0.0f;
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;
554 }
555 if(cov_x < 0.0f) {
556 swap(maxcol_r, mincol_r);
557 }
558 if(cov_y < 0.0f) {
559 swap(maxcol_g, mincol_g);
560 }
561
562 // encode both endpoints into 565 color format
563 const u32 max_code = encode_endpoint(maxcol_r, maxcol_g, maxcol_b);
564 const u32 min_code = encode_endpoint(mincol_r, mincol_g, mincol_b);
565
566 // swap palette end colors if 'max' code is less than 'min' color code
567 // (Palette color #3 would otherwise be interpreted as 'transparent'.)
568 const bool swap_end_colors = max_code < min_code;
569
570 // encode the palette into 32 bits (Only 2 end colors are stored.)
571 const u32 palette_code = swap_end_colors ?
572 min_code + (max_code << 16): max_code + (min_code << 16);
573
574 // pack palette color indices (if both endpoint colors are not equal)
575 u32 indices = 0;
576 if(max_code != min_code) {
577 // project each color to line maxcol-mincol, represent it as
578 // "mincol + t * (maxcol - mincol)" and then use 't' to find closest
579 // palette color index.
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;
589
590 // for each pixel color:
591 for(int i = 0; i < 16; i++) {
592 // get 't' for the color
593 const float col_t = r[i] * t_r + g[i] * t_g + b[i] * t_b - t_bias;
594
595 // scale the range of the 't' to [0..3] and convert to integer
596 // to get the index of palette color
597 const u32 col_idx = (u32)(3.0f * __saturatef(col_t) + 0.5f);
598
599 // pack the color palette index with others
600 indices += col_idx << (i * 2);
601 }
602 }
603
604 // possibly invert indices if end colors must be swapped
605 if(swap_end_colors) {
606 indices = ~indices;
607 }
608
609 // substitute all packed indices (each index is packed into two bits)
610 // 00 -> 00, 01 -> 10, 10 -> 11 and 11 -> 01
611 const u32 lsbs = indices & 0x55555555;
612 const u32 msbs = indices & 0xaaaaaaaa;
613 indices = msbs ^ (2 * lsbs + (msbs >> 1));
614
615 // compose and save output
616 ((uint2*)out)[block_idx] = make_uint2(palette_code, indices);
617}
618
619
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) {
624 // coordinates of this thread's 4x4 block
625 const int block_idx_x = threadIdx.x + blockIdx.x * blockDim.x;
626 const int block_idx_y = threadIdx.y + blockIdx.y * blockDim.y;
627
628 // coordinates of block's top-left pixel
629 const int block_x = block_idx_x * 4;
630 const int block_y = block_idx_y * 4;
631
632 // raster order index of the block
633 const int block_idx = block_idx_x + (size_x >> 2) * block_idx_y;
634
635 // skip if out of bounds
636 if(block_y >= size_y || block_x >= size_x) {
637 return;
638 }
639
640 // samples of 16 pixels
641 float r[16];
642 float g[16];
643 float b[16];
644
645 // load RGB samples for all 16 input pixels
646 const int src_stride = (size_x >> 2) * 3;
647 for(int y = 0; y < 4; y++) {
648 // offset of loaded pixels in the buffer
649 const int load_offset = y * 4;
650
651 // pointer to source of this input row
652 int row_idx = block_y + y;
653 if(VERTICAL_MIRRORING) {
654 row_idx = size_y - 1 - row_idx;
655 }
656 const uchar4 * const row_src = (uchar4*)src
657 + src_stride * row_idx
658 + block_idx_x * 3;
659
660 // load all 4 3component pixels of the row
661 const uchar4 p0 = row_src[0];
662 const uchar4 p1 = row_src[1];
663 const uchar4 p2 = row_src[2];
664
665 // pixel #0
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;
669
670 // pixel #1
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;
674
675 // pixel #2
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;
679
680 // pixel #3
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;
684 }
685
686 // transform colors from YUV to RGB if required
687 if(YUV_TO_RGB) {
688 for(int i = 0; i < 16; i++) {
689 yuv_to_rgb(r[i], g[i], b[i]);
690 }
691 }
692
693 // Select the right DXT type transform
694 dxt_encode<DXT_TYPE>(out, block_idx, r, g, b);
695}
696
697__global__ static void yuv422_to_yuv444_kernel(const void * src, void * out, int pix_count) {
698 // coordinates of this thread
699 const int block_idx_x = threadIdx.x + blockIdx.x * blockDim.x;
700
701 // skip if out of bounds
702 if(block_idx_x >= pix_count / 2) {
703 return;
704 }
705
706 uchar4 *this_src = ((uchar4 *) src) + block_idx_x * 2;
707 uchar4 *this_out = ((uchar4 *) out) + block_idx_x * 3;
708
709 uchar4 pix12 = this_src[0];
710 uchar4 pix34 = this_src[1];
711
712 uchar4 out_pix[3];
713 out_pix[0].x = pix12.y;
714 out_pix[0].y = pix12.x;
715 out_pix[0].z = pix12.z;
716
717 out_pix[0].w = pix12.w;
718 out_pix[1].x = pix12.x;
719 out_pix[1].y = pix12.z;
720
721 out_pix[1].z = pix34.y;
722 out_pix[1].w = pix34.x;
723 out_pix[2].x = pix34.z;
724
725 out_pix[2].y = pix34.w;
726 out_pix[2].z = pix34.x;
727 out_pix[2].w = pix34.z;
728
729 this_out[0] = out_pix[0];
730 this_out[1] = out_pix[1];
731 this_out[2] = out_pix[2];
732}
733
735template <bool YUV_TO_RGB, int DXT_TYPE>
736static int dxt_launch(const void * src, void * out, int sx, int sy, cudaStream_t str) {
737 // vertical mirroring?
738 bool mirrored = false;
739 if(sy < 0) {
740 mirrored = true;
741 sy = -sy;
742 }
743
744 // check image size and alignment
745 if((sx & 3) || (sy & 3) || (15 & (size_t)src) || (7 & (size_t)out)) {
746 return -1;
747 }
748
749 // grid and threadblock sizes
750 const dim3 tsiz(16, 16);
751 const dim3 gsiz((sx + tsiz.x - 1) / tsiz.x, (sy + tsiz.y - 1) / tsiz.y);
752
753 // launch kernel, sync and check the result
754 if(mirrored) {
755 dxt_kernel<YUV_TO_RGB, true, DXT_TYPE><<<gsiz, tsiz, 0, str>>>(src, out, sx, sy);
756 } else {
757 dxt_kernel<YUV_TO_RGB, false, DXT_TYPE><<<gsiz, tsiz, 0, str>>>(src, out, sx, sy);
758 }
759 return cudaSuccess != cudaStreamSynchronize(str) ? -3 : 0;
760}
761
762int cuda_yuv422_to_yuv444(const void * src, void * out,
763 int pix_count, cuda_wrapper_stream_t str) {
764 // grid and threadblock sizes
765 const dim3 tsiz(64, 1);
766 int thread_count = pix_count / 4; // we process block of 4 pixels
767 const dim3 gsiz((thread_count + tsiz.x - 1) / tsiz.x, 1);
768 yuv422_to_yuv444_kernel<<<gsiz, tsiz, 0, (cudaStream_t) str>>>(src, out, pix_count);
769 return cudaSuccess != cudaStreamSynchronize((cudaStream_t) str) ? -3 : 0;
770}
771
782int cuda_rgb_to_dxt1(const void * src, void * out,
783 int size_x, int size_y, cuda_wrapper_stream_t stream) {
784 return dxt_launch<false, 1>(src, out, size_x, size_y, (cudaStream_t) stream);
785}
786
787
799int cuda_yuv_to_dxt1(const void * src, void * out,
800 int size_x, int size_y, cuda_wrapper_stream_t stream) {
801 return dxt_launch<true, 1>(src, out, size_x, size_y, (cudaStream_t) stream);
802}
803
804
816int cuda_rgb_to_dxt6(const void * src, void * out,
817 int size_x, int size_y, cuda_wrapper_stream_t stream) {
818 return dxt_launch<false, 6>(src, out, size_x, size_y, (cudaStream_t) stream);
819}
820
821int cuda_yuv_to_dxt6(const void * src, void * out,
822 int size_x, int size_y, cuda_wrapper_stream_t stream) {
823 return dxt_launch<true, 6>(src, out, size_x, size_y, (cudaStream_t) stream);
824}
825
static __device__ void InsetYBBox(float &mincol, float &maxcol)
Definition cuda_dxt.cu:176
u32 UINT
Definition cuda_dxt.cu:13
unsigned int u32
Definition cuda_dxt.cu:12
static __device__ uvec2 EmitAlphaIndicesYCoCgDXT5(vec3 block[16], float minAlpha, float maxAlpha)
Definition cuda_dxt.cu:360
static __device__ vec3 ConvertRGBToYCoCg(vec3 color)
Definition cuda_dxt.cu:141
static __device__ vec3 lerp(const vec3 &a, const vec3 &b, const float q)
Definition cuda_dxt.cu:126
__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.
Definition cuda_dxt.cu:456
static int dxt_launch(const void *src, void *out, int sx, int sy, cudaStream_t str)
Compute grid size and launch DXT kernel.
Definition cuda_dxt.cu:736
static __device__ void InsetCoCgBBox(vec2 &mincol, vec2 &maxcol)
Definition cuda_dxt.cu:182
static __device__ float colorDistance(vec2 c0, vec2 c1)
Definition cuda_dxt.cu:154
static __device__ void FindMinMaxColorsBox(vec3 block[16], vec3 &mincol, vec3 &maxcol)
Definition cuda_dxt.cu:159
static __device__ float dot(const vec3 &a, const vec3 &b)
Definition cuda_dxt.cu:106
__device__ void dxt_encode< 6 >(void *out, const int block_idx, float r[16], float g[16], float b[16])
Definition cuda_dxt.cu:472
static __device__ UINT EmitEndPointsYCoCgDXT5(float &mincol_r, float &mincol_g, float &maxcol_r, float &maxcol_g, UINT scale)
Definition cuda_dxt.cu:272
static __device__ u32 encode_endpoint(float &r, float &g, float &b)
Encodes color palette endpoint into 565 code and adjusts input values.
Definition cuda_dxt.cu:424
static __device__ bool SelectYCoCgDiagonal(const vec3 block[16], vec2 minColor, vec2 maxColor)
Definition cuda_dxt.cu:260
static __device__ vec2 abs(const vec2 &v)
Definition cuda_dxt.cu:118
int cuda_yuv_to_dxt1(const void *src, void *out, int size_x, int size_y, cuda_wrapper_stream_t stream)
Definition cuda_dxt.cu:799
int cuda_yuv_to_dxt6(const void *src, void *out, int size_x, int size_y, cuda_wrapper_stream_t stream)
Definition cuda_dxt.cu:821
static __device__ void yuv_to_rgb(float &r, float &g, float &b)
Transform YUV to RGB.
Definition cuda_dxt.cu:444
static __device__ UINT ScaleYCoCg(vec2 minColor, vec2 maxColor)
Definition cuda_dxt.cu:241
int cuda_rgb_to_dxt6(const void *src, void *out, int size_x, int size_y, cuda_wrapper_stream_t stream)
Definition cuda_dxt.cu:816
static __device__ UINT EmitIndicesYCoCgDXT5(vec3 block[16], vec2 mincol, vec2 maxcol)
Definition cuda_dxt.cu:315
__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.
Definition cuda_dxt.cu:513
int cuda_rgb_to_dxt1(const void *src, void *out, int size_x, int size_y, cuda_wrapper_stream_t stream)
Definition cuda_dxt.cu:782
static __global__ void dxt_kernel(const void *src, void *out, int size_x, int size_y)
Definition cuda_dxt.cu:623
static __device__ vec2 clamp(const vec2 &v, float min_val, float max_val)
Definition cuda_dxt.cu:110
static __device__ vec3 round(const vec3 &v)
Definition cuda_dxt.cu:122
int cuda_yuv422_to_yuv444(const void *src, void *out, int pix_count, cuda_wrapper_stream_t str)
Definition cuda_dxt.cu:762
static __device__ UINT EmitAlphaEndPointsYCoCgDXT5(float mincol, float maxcol)
Definition cuda_dxt.cu:350
static __global__ void yuv422_to_yuv444_kernel(const void *src, void *out, int pix_count)
Definition cuda_dxt.cu:697
static __device__ const float offset
Definition cuda_dxt.cu:139
Interface of DXT compression CUDA implementation.
#define cudaSuccess
void * cuda_wrapper_stream_t
#define min(a, b)
Definition rtp.c:99
#define max(a, b)
Definition rtp.c:98
__device__ uvec2(u32 x, u32 y)
Definition cuda_dxt.cu:50
__device__ uvec2(u32 n=0)
Definition cuda_dxt.cu:51
u32 g
Definition cuda_dxt.cu:49
u32 r
Definition cuda_dxt.cu:49
__device__ uvec3(u32 r, u32 g, u32 b)
Definition cuda_dxt.cu:20
u32 g
Definition cuda_dxt.cu:19
u32 b
Definition cuda_dxt.cu:19
__device__ uvec3(u32 n=0)
Definition cuda_dxt.cu:21
u32 r
Definition cuda_dxt.cu:19
float r
Definition cuda_dxt.cu:26
__device__ vec2(float x, float y)
Definition cuda_dxt.cu:27
__device__ vec2 operator+(const vec2 &o) const
Definition cuda_dxt.cu:31
__device__ vec2 operator*(const vec2 &v) const
Definition cuda_dxt.cu:34
__device__ vec2 operator*(const float n) const
Definition cuda_dxt.cu:37
float g
Definition cuda_dxt.cu:26
__device__ vec2 operator/(const float n) const
Definition cuda_dxt.cu:43
__device__ vec2(float n=0.0f)
Definition cuda_dxt.cu:28
__device__ vec2 operator-(const vec2 &o) const
Definition cuda_dxt.cu:40
__device__ vec3 operator/(const float n) const
Definition cuda_dxt.cu:73
__device__ vec3 operator-(const vec3 &o) const
Definition cuda_dxt.cu:70
__device__ vec3 operator*(const float n) const
Definition cuda_dxt.cu:67
float b
Definition cuda_dxt.cu:56
__device__ vec2 gb() const
Definition cuda_dxt.cu:79
__device__ vec3 operator*(const vec3 &v) const
Definition cuda_dxt.cu:64
__device__ vec3(const uvec3 &v)
Definition cuda_dxt.cu:60
__device__ vec3(float n=0.0f)
Definition cuda_dxt.cu:58
__device__ vec3 operator+(const vec3 &o) const
Definition cuda_dxt.cu:61
__device__ vec3(float x, float y, float z)
Definition cuda_dxt.cu:57
__device__ vec3(const vec2 &v)
Definition cuda_dxt.cu:59