Loading...
Searching...
No Matches
TextureConversion.hpp
1#pragma once
2
3#include <QtGui/private/qrhi_p.h>
4#include <avnd/concepts/gfx.hpp>
5#include <Crousti/TextureFormat.hpp>
6
7#include <QFloat16>
8
9namespace gpp::qrhi
10{
11
12inline void toRGB(QRhiTexture::Format in_format, QByteArray& buf, int width, int height)
13{
14 const int N = width * height;
15 switch(in_format)
16 {
17 case QRhiTexture::RGBA8:
18 {
19 // RGBA to
20 // RGB
21 uint8_t* data = reinterpret_cast<uint8_t*>(buf.data());
22 int write_i = 0;
23 int read_i = 0;
24 for(int i = 0; i < N; i++)
25 {
26 data[write_i + 0] = data[read_i + 0];
27 data[write_i + 1] = data[read_i + 1];
28 data[write_i + 2] = data[read_i + 2];
29 write_i += 3;
30 read_i += 4;
31 }
32
33 buf.resize(N * 3);
34 break;
35 }
36
37 case QRhiTexture::BGRA8:
38 {
39 // BGRA to
40 // RGB
41 uint8_t* data = reinterpret_cast<uint8_t*>(buf.data());
42 int write_i = 0;
43 int read_i = 0;
44 for(int i = 0; i < N; i++)
45 {
46 data[write_i + 0] = data[read_i + 2];
47 data[write_i + 1] = data[read_i + 1];
48 data[write_i + 2] = data[read_i + 0];
49 write_i += 3;
50 read_i += 4;
51 }
52
53 buf.resize(N * 3);
54 break;
55 }
56
57 case QRhiTexture::RED_OR_ALPHA8:
58 case QRhiTexture::R8:
59 {
60 // R to
61 // RRR
62 uint8_t* data = reinterpret_cast<uint8_t*>(buf.data());
63 int write_i = 0;
64 int read_i = 0;
65
66#if QT_VERSION > QT_VERSION_CHECK(6,8,0)
67 buf.resizeForOverwrite(N * 3);
68#else
69 buf.resize(N * 3);
70#endif
71 for(int i = N - 1; i >= 0; i--)
72 {
73 auto gray = data[i];
74 data[i * 3 + 0] = gray;
75 data[i * 3 + 1] = gray;
76 data[i * 3 + 2] = gray;
77 }
78 break;
79 }
80
81 case QRhiTexture::R16: // x
82 {
83 // R to
84 // RRR
85 QByteArray rgb(N*3, Qt::Uninitialized);
86
87 auto src = reinterpret_cast<const uint16_t*>(buf.constData());
88 auto dst = reinterpret_cast<uint8_t*>(rgb.data());
89
90 for(int i = 0; i < N; i++)
91 {
92 uint8_t gray = (uint32_t(src[i]) * 255) / 65535;
93
94 dst[i * 3 + 0] = gray;
95 dst[i * 3 + 1] = gray;
96 dst[i * 3 + 2] = gray;
97 }
98
99 buf = rgb;
100 break;
101 }
102 case QRhiTexture::RGBA16F:
103 {
104 // RGBA to
105 // RGB
106 auto src = reinterpret_cast<const qfloat16*>(buf.constData());
107 unsigned char* data = (unsigned char*)buf.data();
108 int write_i = 0;
109 int read_i = 0;
110 for(int i = 0; i < N; i++)
111 {
112 data[write_i + 0] = qBound(0, int(src[read_i + 0] * 255.0f), 255);
113 data[write_i + 1] = qBound(0, int(src[read_i + 1] * 255.0f), 255);
114 data[write_i + 2] = qBound(0, int(src[read_i + 2] * 255.0f), 255);
115 write_i += 3;
116 read_i += 4;
117 }
118 buf.resize(N * 3);
119 break;
120 }
121 case QRhiTexture::RGBA32F:
122 {
123 // RGBA to
124 // RGB
125 auto src = reinterpret_cast<const float*>(buf.constData());
126 unsigned char* data = (unsigned char*)buf.data();
127 int write_i = 0;
128 int read_i = 0;
129 for(int i = 0; i < N; i++)
130 {
131 data[write_i + 0] = qBound(0, int(src[read_i + 0] * 255.0f), 255);
132 data[write_i + 1] = qBound(0, int(src[read_i + 1] * 255.0f), 255);
133 data[write_i + 2] = qBound(0, int(src[read_i + 2] * 255.0f), 255);
134 write_i += 3;
135 read_i += 4;
136 }
137 buf.resize(N * 3);
138 break;
139 }
140 case QRhiTexture::R16F:
141 {
142 // R to
143 // RRR
144 buf.resize(N * 3);
145 auto src = reinterpret_cast<const qfloat16*>(buf.constData());
146 unsigned char* dst = (unsigned char*)buf.data();
147 for(int i = N - 1; i >= 0; i--)
148 {
149 uint8_t gray = qBound(0, int(src[i] * 255.0f), 255);
150 dst[i * 3 + 0] = gray;
151 dst[i * 3 + 1] = gray;
152 dst[i * 3 + 2] = gray;
153 }
154 break;
155 }
156 case QRhiTexture::R32F:
157 {
158 // R32F to RGB8
159 buf.resize(N * 3);
160 auto src = reinterpret_cast<const float*>(buf.constData());
161 unsigned char* dst = (unsigned char*)buf.data();
162 int write_i = 0;
163 for(int i = 0; i < N; i++)
164 {
165 uint8_t gray = qBound(0, int(src[i] * 255.0f), 255);
166 dst[write_i + 0] = gray;
167 dst[write_i + 1] = gray;
168 dst[write_i + 2] = gray;
169 write_i += 3;
170 }
171 buf.resize(N * 3);
172 break;
173 }
174
175#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
176 case QRhiTexture::R8UI:
177 {
178 // R8UI to RGB8 (already uint8, just expand)
179 buf.resize(N * 3);
180 unsigned char* data = (unsigned char*)buf.data();
181 for(int i = N - 1; i >= 0; i--)
182 {
183 auto gray = data[i];
184 data[i * 3 + 0] = gray;
185 data[i * 3 + 1] = gray;
186 data[i * 3 + 2] = gray;
187 }
188 break;
189 }
190 case QRhiTexture::R32UI:
191 {
192 // R32UI to
193 // RGB8
194 QByteArray rgb(N * 3, Qt::Uninitialized);
195 auto src = reinterpret_cast<const uint32_t*>(buf.constData());
196 auto dst = reinterpret_cast<uint8_t*>(rgb.data());
197 for(int i = 0; i < N; i++)
198 {
199 uint8_t gray = (uint64_t(src[i]) * 255) / 4294967295UL;
200 dst[i * 3 + 0] = gray;
201 dst[i * 3 + 1] = gray;
202 dst[i * 3 + 2] = gray;
203 }
204 buf = rgb;
205 break;
206 }
207 case QRhiTexture::RGBA32UI:
208 {
209 // RGBA32UI to
210 // RGB8
211 QByteArray rgb(N * 3, Qt::Uninitialized);
212 auto src = reinterpret_cast<const uint32_t*>(buf.constData());
213 auto dst = reinterpret_cast<uint8_t*>(rgb.data());
214 int write_i = 0;
215 int read_i = 0;
216 for(int i = 0; i < N; i++)
217 {
218 // Clamp uint32 values to uint8 range
219 dst[write_i + 0] = src[read_i + 0] > 255 ? 255 : src[read_i + 0];
220 dst[write_i + 1] = src[read_i + 1] > 255 ? 255 : src[read_i + 1];
221 dst[write_i + 2] = src[read_i + 2] > 255 ? 255 : src[read_i + 2];
222 write_i += 3;
223 read_i += 4;
224 }
225 buf = rgb;
226 break;
227 }
228#endif
229
230 default:
231 if(buf.size() < N * 3)
232 buf.resize(N * 3);
233 break;
234 }
235}
236
237inline void toRGBA(QRhiTexture::Format in_format, QByteArray& buf, int width, int height)
238{
239 const int N = width * height;
240 switch(in_format)
241 {
242 case QRhiTexture::RGBA8:
243 break;
244
245 case QRhiTexture::BGRA8:
246 {
247 // BGRA to RGBA (swap R and B in-place)
248 uint8_t* data = reinterpret_cast<uint8_t*>(buf.data());
249 for(int i = 0; i < N; i++)
250 {
251 std::swap(data[i * 4 + 0], data[i * 4 + 2]);
252 }
253 break;
254 }
255
256 case QRhiTexture::RED_OR_ALPHA8:
257 case QRhiTexture::R8:
258 {
259#if QT_VERSION > QT_VERSION_CHECK(6,8,0)
260 buf.resizeForOverwrite(N * 4);
261#else
262 buf.resize(N * 4);
263#endif
264 uint8_t* data = reinterpret_cast<uint8_t*>(buf.data());
265 for(int i = N - 1; i >= 0; i--)
266 {
267 auto gray = data[i];
268 data[i * 4 + 0] = gray;
269 data[i * 4 + 1] = gray;
270 data[i * 4 + 2] = gray;
271 data[i * 4 + 3] = 255;
272 }
273 break;
274 }
275
276 case QRhiTexture::R16:
277 {
278 // R16 to RGBA8
279 buf.resize(N * 4);
280 auto src = reinterpret_cast<const uint16_t*>(buf.constData());
281 auto dst = reinterpret_cast<uint8_t*>(buf.data());
282 for(int i = N - 1; i >= 0; i--)
283 {
284 uint8_t gray = (uint32_t(src[i]) * 255) / 65535;
285 dst[i * 4 + 0] = gray;
286 dst[i * 4 + 1] = gray;
287 dst[i * 4 + 2] = gray;
288 dst[i * 4 + 3] = 255;
289 }
290 break;
291 }
292
293 case QRhiTexture::RGBA16F:
294 {
295 // RGBA16F to RGBA8
296 auto src = reinterpret_cast<const qfloat16*>(buf.constData());
297 auto dst = reinterpret_cast<uint8_t*>(buf.data());
298 int write_i = 0;
299 int read_i = 0;
300 for(int i = 0; i < N; i++)
301 {
302 dst[write_i + 0] = qBound(0, int(src[read_i + 0] * 255.0f), 255);
303 dst[write_i + 1] = qBound(0, int(src[read_i + 1] * 255.0f), 255);
304 dst[write_i + 2] = qBound(0, int(src[read_i + 2] * 255.0f), 255);
305 dst[write_i + 3] = qBound(0, int(src[read_i + 3] * 255.0f), 255);
306 write_i += 4;
307 read_i += 4;
308 }
309 buf.resize(N * 4);
310 break;
311 }
312
313 case QRhiTexture::RGBA32F:
314 {
315 // RGBA32F to RGBA8
316 auto src = reinterpret_cast<const float*>(buf.constData());
317 auto dst = reinterpret_cast<uint8_t*>(buf.data());
318 int write_i = 0;
319 int read_i = 0;
320 for(int i = 0; i < N; i++)
321 {
322 dst[write_i + 0] = qBound(0, int(src[read_i + 0] * 255.0f), 255);
323 dst[write_i + 1] = qBound(0, int(src[read_i + 1] * 255.0f), 255);
324 dst[write_i + 2] = qBound(0, int(src[read_i + 2] * 255.0f), 255);
325 dst[write_i + 3] = qBound(0, int(src[read_i + 3] * 255.0f), 255);
326 write_i += 4;
327 read_i += 4;
328 }
329 buf.resize(N * 4);
330 break;
331 }
332
333 case QRhiTexture::R16F:
334 {
335 // R16F to RGBA8
336 buf.resize(N * 4);
337 auto src = reinterpret_cast<const qfloat16*>(buf.constData());
338 auto dst = reinterpret_cast<uint8_t*>(buf.data());
339 for(int i = N - 1; i >= 0; i--)
340 {
341 uint8_t gray = qBound(0, int(src[i] * 255.0f), 255);
342 dst[i * 4 + 0] = gray;
343 dst[i * 4 + 1] = gray;
344 dst[i * 4 + 2] = gray;
345 dst[i * 4 + 3] = 255;
346 }
347 break;
348 }
349
350 case QRhiTexture::R32F:
351 {
352 // R32F to RGBA8
353 auto src = reinterpret_cast<const float*>(buf.constData());
354 auto dst = reinterpret_cast<uint8_t*>(buf.data());
355 for(int i = 0; i < N; i++)
356 {
357 uint8_t gray = qBound(0, int(src[i] * 255.0f), 255);
358 dst[i * 4 + 0] = gray;
359 dst[i * 4 + 1] = gray;
360 dst[i * 4 + 2] = gray;
361 dst[i * 4 + 3] = 255;
362 }
363 buf.resize(N * 4);
364 break;
365 }
366
367#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
368 case QRhiTexture::R8UI:
369 {
370 // R8UI to RGBA8
371 buf.resize(N * 4);
372 auto data = reinterpret_cast<uint8_t*>(buf.data());
373 for(int i = N - 1; i >= 0; i--)
374 {
375 auto gray = data[i];
376 data[i * 4 + 0] = gray;
377 data[i * 4 + 1] = gray;
378 data[i * 4 + 2] = gray;
379 data[i * 4 + 3] = 255;
380 }
381 break;
382 }
383
384 case QRhiTexture::R32UI:
385 {
386 // R32UI to RGBA8
387 auto src = reinterpret_cast<const uint32_t*>(buf.constData());
388 auto dst = reinterpret_cast<uint8_t*>(buf.data());
389 for(int i = 0; i < N; i++)
390 {
391 uint8_t gray = (uint64_t(src[i]) * 255) / 4294967295UL;
392 dst[i * 4 + 0] = gray;
393 dst[i * 4 + 1] = gray;
394 dst[i * 4 + 2] = gray;
395 dst[i * 4 + 3] = 255;
396 }
397 buf.resize(N * 4);
398 break;
399 }
400
401 case QRhiTexture::RGBA32UI:
402 {
403 // RGBA32UI to RGBA8
404 auto src = reinterpret_cast<const uint32_t*>(buf.constData());
405 auto dst = reinterpret_cast<uint8_t*>(buf.data());
406 int write_i = 0;
407 int read_i = 0;
408 for(int i = 0; i < N; i++)
409 {
410 dst[write_i + 0] = src[read_i + 0] > 255 ? 255 : src[read_i + 0];
411 dst[write_i + 1] = src[read_i + 1] > 255 ? 255 : src[read_i + 1];
412 dst[write_i + 2] = src[read_i + 2] > 255 ? 255 : src[read_i + 2];
413 dst[write_i + 3] = src[read_i + 3] > 255 ? 255 : src[read_i + 3];
414 write_i += 4;
415 read_i += 4;
416 }
417 buf.resize(N * 4);
418 break;
419 }
420#endif
421
422 default:
423 if(buf.size() < N * 4)
424 buf.resize(N * 4);
425 break;
426 }
427}
428
429inline void toR8(QRhiTexture::Format in_format, QByteArray& buf, int width, int height)
430{
431 const int N = width * height;
432 switch(in_format)
433 {
434 case QRhiTexture::R8:
435 case QRhiTexture::RED_OR_ALPHA8:
436#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
437 case QRhiTexture::R8UI:
438#endif
439 break;
440
441 case QRhiTexture::RGBA8:
442 {
443 // RGBA8 to R8
444 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
445 auto dst = reinterpret_cast<uint8_t*>(buf.data());
446 for(int i = 0; i < N; i++)
447 {
448 dst[i] = (src[i * 4 + 0] * 299 + src[i * 4 + 1] * 587 + src[i * 4 + 2] * 114) / 1000;
449 // Alternatives:
450 // average: dst[i] = (src[i * 4 + 0] + src[i * 4 + 1] + src[i * 4 + 2]) / 3;
451 // R channel: dst[i] = src[i * 4 + 0];
452 }
453 buf.resize(N);
454 break;
455 }
456
457 case QRhiTexture::BGRA8:
458 {
459 // BGRA8 to R8
460 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
461 auto dst = reinterpret_cast<uint8_t*>(buf.data());
462 for(int i = 0; i < N; i++)
463 {
464 dst[i] = (src[i * 4 + 2] * 299 + src[i * 4 + 1] * 587 + src[i * 4 + 0] * 114) / 1000;
465 }
466 buf.resize(N);
467 break;
468 }
469
470 case QRhiTexture::R16:
471 {
472 // R16 to R8
473 auto src = reinterpret_cast<const uint16_t*>(buf.constData());
474 auto dst = reinterpret_cast<uint8_t*>(buf.data());
475 for(int i = 0; i < N; i++)
476 {
477 dst[i] = (uint32_t(src[i]) * 255) / 65535;
478 }
479 buf.resize(N);
480 break;
481 }
482
483 case QRhiTexture::RGBA16F:
484 {
485 // RGBA16F to R8
486 auto src = reinterpret_cast<const qfloat16*>(buf.constData());
487 auto dst = reinterpret_cast<uint8_t*>(buf.data());
488 for(int i = 0; i < N; i++)
489 {
490 float gray = (src[i * 4 + 0] * 0.299f + src[i * 4 + 1] * 0.587f + src[i * 4 + 2] * 0.114f);
491 dst[i] = qBound(0, int(gray * 255.0f), 255);
492 }
493 buf.resize(N);
494 break;
495 }
496
497 case QRhiTexture::RGBA32F:
498 {
499 // RGBA32F to R8
500 auto src = reinterpret_cast<const float*>(buf.constData());
501 auto dst = reinterpret_cast<uint8_t*>(buf.data());
502 for(int i = 0; i < N; i++)
503 {
504 float gray = (src[i * 4 + 0] * 0.299f + src[i * 4 + 1] * 0.587f + src[i * 4 + 2] * 0.114f);
505 dst[i] = qBound(0, int(gray * 255.0f), 255);
506 }
507 buf.resize(N);
508 break;
509 }
510
511 case QRhiTexture::R16F:
512 {
513 // R16F to R8
514 auto src = reinterpret_cast<const qfloat16*>(buf.constData());
515 auto dst = reinterpret_cast<uint8_t*>(buf.data());
516 for(int i = 0; i < N; i++)
517 {
518 dst[i] = qBound(0, int(src[i] * 255.0f), 255);
519 }
520 buf.resize(N);
521 break;
522 }
523
524 case QRhiTexture::R32F:
525 {
526 // R32F to R8
527 auto src = reinterpret_cast<const float*>(buf.constData());
528 auto dst = reinterpret_cast<uint8_t*>(buf.data());
529 for(int i = 0; i < N; i++)
530 {
531 dst[i] = qBound(0, int(src[i] * 255.0f), 255);
532 }
533 buf.resize(N);
534 break;
535 }
536
537#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
538 case QRhiTexture::R32UI:
539 {
540 // R32UI to R8
541 auto src = reinterpret_cast<const uint32_t*>(buf.constData());
542 auto dst = reinterpret_cast<uint8_t*>(buf.data());
543 for(int i = 0; i < N; i++)
544 {
545 dst[i] = (uint64_t(src[i]) * 255) / 4294967295UL;
546 }
547 buf.resize(N);
548 break;
549 }
550
551 case QRhiTexture::RGBA32UI:
552 {
553 // RGBA32UI to R8
554 auto src = reinterpret_cast<const uint32_t*>(buf.constData());
555 auto dst = reinterpret_cast<uint8_t*>(buf.data());
556 for(int i = 0; i < N; i++)
557 {
558 uint32_t gray = (src[i * 4 + 0] * 299 + src[i * 4 + 1] * 587 + src[i * 4 + 2] * 114) / 1000;
559 dst[i] = gray > 255 ? 255 : gray;
560 }
561 buf.resize(N);
562 break;
563 }
564#endif
565
566 default:
567 if(buf.size() > N)
568 buf.resize(N);
569 break;
570 }
571}
572inline void toRGBA32F(QRhiTexture::Format in_format, QByteArray& buf, int width, int height)
573{
574 const int N = width * height;
575 switch(in_format)
576 {
577 case QRhiTexture::RGBA32F:
578 break;
579
580 case QRhiTexture::RGBA8:
581 {
582 // RGBA8 to RGBA32F
583 buf.resize(N * 16);
584 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
585 auto dst = reinterpret_cast<float*>(buf.data());
586 for(int i = N - 1; i >= 0; i--)
587 {
588 dst[i * 4 + 0] = src[i * 4 + 0] / 255.0f;
589 dst[i * 4 + 1] = src[i * 4 + 1] / 255.0f;
590 dst[i * 4 + 2] = src[i * 4 + 2] / 255.0f;
591 dst[i * 4 + 3] = src[i * 4 + 3] / 255.0f;
592 }
593 break;
594 }
595
596 case QRhiTexture::BGRA8:
597 {
598 // BGRA8 to RGBA32F
599 buf.resize(N * 16);
600 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
601 auto dst = reinterpret_cast<float*>(buf.data());
602 for(int i = N - 1; i >= 0; i--)
603 {
604 dst[i * 4 + 0] = src[i * 4 + 2] / 255.0f; // B -> R
605 dst[i * 4 + 1] = src[i * 4 + 1] / 255.0f; // G -> G
606 dst[i * 4 + 2] = src[i * 4 + 0] / 255.0f; // R -> B
607 dst[i * 4 + 3] = src[i * 4 + 3] / 255.0f; // A -> A
608 }
609 break;
610 }
611
612 case QRhiTexture::RED_OR_ALPHA8:
613 case QRhiTexture::R8:
614 {
615 // R8 to RGBA32F
616 buf.resize(N * 16);
617 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
618 auto dst = reinterpret_cast<float*>(buf.data());
619 for(int i = N - 1; i >= 0; i--)
620 {
621 float gray = src[i] / 255.0f;
622 dst[i * 4 + 0] = gray;
623 dst[i * 4 + 1] = gray;
624 dst[i * 4 + 2] = gray;
625 dst[i * 4 + 3] = 1.0f;
626 }
627 break;
628 }
629
630 case QRhiTexture::R16:
631 {
632 // R16 to RGBA32F
633 buf.resize(N * 16);
634 auto src = reinterpret_cast<const uint16_t*>(buf.constData());
635 auto dst = reinterpret_cast<float*>(buf.data());
636 for(int i = N - 1; i >= 0; i--)
637 {
638 float gray = src[i] / 65535.0f;
639 dst[i * 4 + 0] = gray;
640 dst[i * 4 + 1] = gray;
641 dst[i * 4 + 2] = gray;
642 dst[i * 4 + 3] = 1.0f;
643 }
644 break;
645 }
646
647 case QRhiTexture::RGBA16F:
648 {
649 // RGBA16F to RGBA32F
650 buf.resize(N * 16);
651 auto src = reinterpret_cast<const qfloat16*>(buf.constData());
652 auto dst = reinterpret_cast<float*>(buf.data());
653 for(int i = N - 1; i >= 0; i--)
654 {
655 dst[i * 4 + 0] = src[i * 4 + 0];
656 dst[i * 4 + 1] = src[i * 4 + 1];
657 dst[i * 4 + 2] = src[i * 4 + 2];
658 dst[i * 4 + 3] = src[i * 4 + 3];
659 }
660 break;
661 }
662
663 case QRhiTexture::R16F:
664 {
665 // R16F to RGBA32F
666 buf.resize(N * 16);
667 auto src = reinterpret_cast<const qfloat16*>(buf.constData());
668 auto dst = reinterpret_cast<float*>(buf.data());
669 for(int i = N - 1; i >= 0; i--)
670 {
671 float gray = src[i];
672 dst[i * 4 + 0] = gray;
673 dst[i * 4 + 1] = gray;
674 dst[i * 4 + 2] = gray;
675 dst[i * 4 + 3] = 1.0f;
676 }
677 break;
678 }
679
680 case QRhiTexture::R32F:
681 {
682 // R32F to RGBA32F
683 buf.resize(N * 16);
684 auto src = reinterpret_cast<const float*>(buf.constData());
685 auto dst = reinterpret_cast<float*>(buf.data());
686 for(int i = N - 1; i >= 0; i--)
687 {
688 float gray = src[i];
689 dst[i * 4 + 0] = gray;
690 dst[i * 4 + 1] = gray;
691 dst[i * 4 + 2] = gray;
692 dst[i * 4 + 3] = 1.0f;
693 }
694 break;
695 }
696
697#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
698 case QRhiTexture::R8UI:
699 {
700 // R8UI to RGBA32F
701 buf.resize(N * 16);
702 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
703 auto dst = reinterpret_cast<float*>(buf.data());
704 for(int i = N - 1; i >= 0; i--)
705 {
706 float gray = src[i] / 255.0f;
707 dst[i * 4 + 0] = gray;
708 dst[i * 4 + 1] = gray;
709 dst[i * 4 + 2] = gray;
710 dst[i * 4 + 3] = 1.0f;
711 }
712 break;
713 }
714
715 case QRhiTexture::R32UI:
716 {
717 // R32UI to RGBA32F
718 buf.resize(N * 16);
719 auto src = reinterpret_cast<const uint32_t*>(buf.constData());
720 auto dst = reinterpret_cast<float*>(buf.data());
721 for(int i = N - 1; i >= 0; i--)
722 {
723 float gray = src[i] / 4294967295.0f;
724 dst[i * 4 + 0] = gray;
725 dst[i * 4 + 1] = gray;
726 dst[i * 4 + 2] = gray;
727 dst[i * 4 + 3] = 1.0f;
728 }
729 break;
730 }
731
732 case QRhiTexture::RGBA32UI:
733 {
734 // RGBA32UI to RGBA32F
735 auto src = reinterpret_cast<const uint32_t*>(buf.constData());
736 auto dst = reinterpret_cast<float*>(buf.data());
737 for(int i = 0; i < N; i++)
738 {
739 dst[i * 4 + 0] = src[i * 4 + 0] / 4294967295.0f;
740 dst[i * 4 + 1] = src[i * 4 + 1] / 4294967295.0f;
741 dst[i * 4 + 2] = src[i * 4 + 2] / 4294967295.0f;
742 dst[i * 4 + 3] = src[i * 4 + 3] / 4294967295.0f;
743 }
744 break;
745 }
746#endif
747
748 default:
749 if(buf.size() < N * 16)
750 buf.resize(N * 16);
751 break;
752 }
753}
754inline void toR16(QRhiTexture::Format in_format, QByteArray& buf, int width, int height)
755{
756 const int N = width * height;
757 switch(in_format)
758 {
759 case QRhiTexture::R16:
760 break;
761
762 case QRhiTexture::RGBA8:
763 {
764 // RGBA8 to R16
765 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
766 auto dst = reinterpret_cast<uint16_t*>(buf.data());
767 for(int i = 0; i < N; i++)
768 {
769 // Convert to grayscale using luminance formula
770 uint32_t gray = (src[i * 4 + 0] * 299 + src[i * 4 + 1] * 587 + src[i * 4 + 2] * 114) / 1000;
771 dst[i] = (gray * 65535) / 255;
772 }
773 buf.resize(N * 2);
774 break;
775 }
776
777 case QRhiTexture::BGRA8:
778 {
779 // BGRA8 to R16
780 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
781 auto dst = reinterpret_cast<uint16_t*>(buf.data());
782 for(int i = 0; i < N; i++)
783 {
784 uint32_t gray = (src[i * 4 + 2] * 299 + src[i * 4 + 1] * 587 + src[i * 4 + 0] * 114) / 1000;
785 dst[i] = (gray * 65535) / 255;
786 }
787 buf.resize(N * 2);
788 break;
789 }
790
791 case QRhiTexture::RED_OR_ALPHA8:
792 case QRhiTexture::R8:
793 {
794 // R8 to R16
795 buf.resize(N * 2);
796 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
797 auto dst = reinterpret_cast<uint16_t*>(buf.data());
798 for(int i = N - 1; i >= 0; i--)
799 {
800 dst[i] = (src[i] * 65535) / 255;
801 }
802 break;
803 }
804
805 case QRhiTexture::RGBA16F:
806 {
807 // RGBA16F to R16
808 auto src = reinterpret_cast<const qfloat16*>(buf.constData());
809 auto dst = reinterpret_cast<uint16_t*>(buf.data());
810 for(int i = 0; i < N; i++)
811 {
812 float gray = (src[i * 4 + 0] * 0.299f + src[i * 4 + 1] * 0.587f + src[i * 4 + 2] * 0.114f);
813 dst[i] = qBound(0, int(gray * 65535.0f), 65535);
814 }
815 buf.resize(N * 2);
816 break;
817 }
818
819 case QRhiTexture::RGBA32F:
820 {
821 // RGBA32F to R16
822 auto src = reinterpret_cast<const float*>(buf.constData());
823 auto dst = reinterpret_cast<uint16_t*>(buf.data());
824 for(int i = 0; i < N; i++)
825 {
826 // Grayscale from RGBA
827 float gray = (src[i * 4 + 0] * 0.299f + src[i * 4 + 1] * 0.587f + src[i * 4 + 2] * 0.114f);
828 dst[i] = qBound(0, int(gray * 65535.0f), 65535);
829 }
830 buf.resize(N * 2);
831 break;
832 }
833
834 case QRhiTexture::R16F:
835 {
836 // R16F to R16
837 auto src = reinterpret_cast<const qfloat16*>(buf.constData());
838 auto dst = reinterpret_cast<uint16_t*>(buf.data());
839 for(int i = 0; i < N; i++)
840 {
841 dst[i] = qBound(0, int(src[i] * 65535.0f), 65535);
842 }
843 break;
844 }
845
846 case QRhiTexture::R32F:
847 {
848 // R32F to R16
849 auto src = reinterpret_cast<const float*>(buf.constData());
850 auto dst = reinterpret_cast<uint16_t*>(buf.data());
851 for(int i = 0; i < N; i++)
852 {
853 dst[i] = qBound(0, int(src[i] * 65535.0f), 65535);
854 }
855 buf.resize(N * 2);
856 break;
857 }
858
859#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
860 case QRhiTexture::R8UI:
861 {
862 // R8UI to R16
863 buf.resize(N * 2);
864 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
865 auto dst = reinterpret_cast<uint16_t*>(buf.data());
866 for(int i = N - 1; i >= 0; i--)
867 {
868 dst[i] = (src[i] * 65535) / 255;
869 }
870 break;
871 }
872
873 case QRhiTexture::R32UI:
874 {
875 // R32UI to R16
876 auto src = reinterpret_cast<const uint32_t*>(buf.constData());
877 auto dst = reinterpret_cast<uint16_t*>(buf.data());
878 for(int i = 0; i < N; i++)
879 {
880 dst[i] = (uint64_t(src[i]) * 65535) / 4294967295UL;
881 }
882 buf.resize(N * 2);
883 break;
884 }
885
886 case QRhiTexture::RGBA32UI:
887 {
888 // RGBA32UI to R16
889 auto src = reinterpret_cast<const uint32_t*>(buf.constData());
890 auto dst = reinterpret_cast<uint16_t*>(buf.data());
891 for(int i = 0; i < N; i++)
892 {
893 uint64_t gray = (uint64_t(src[i * 4 + 0]) * 299 + uint64_t(src[i * 4 + 1]) * 587 + uint64_t(src[i * 4 + 2]) * 114) / 1000;
894 dst[i] = gray > 65535 ? 65535 : gray;
895 }
896 buf.resize(N * 2);
897 break;
898 }
899#endif
900
901 default:
902 if(buf.size() != N * 2)
903 buf.resize(N * 2);
904 break;
905 }
906}
907inline void toR32F(QRhiTexture::Format in_format, QByteArray& buf, int width, int height)
908{
909 const int N = width * height;
910 switch(in_format)
911 {
912 case QRhiTexture::R32F:
913 break;
914
915 case QRhiTexture::RGBA8:
916 {
917 // RGBA8 to R32F
918 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
919 auto dst = reinterpret_cast<float*>(buf.data());
920 for(int i = 0; i < N; i++)
921 {
922 uint32_t gray = (src[i * 4 + 0] * 299 + src[i * 4 + 1] * 587 + src[i * 4 + 2] * 114) / 1000;
923 dst[i] = gray / 255.0f;
924 }
925 break;
926 }
927
928 case QRhiTexture::BGRA8:
929 {
930 // BGRA8 to R32F
931 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
932 auto dst = reinterpret_cast<float*>(buf.data());
933 for(int i = 0; i < N; i++)
934 {
935 // Convert to grayscale (B, G, R, A)
936 uint32_t gray = (src[i * 4 + 2] * 299 + src[i * 4 + 1] * 587 + src[i * 4 + 0] * 114) / 1000;
937 dst[i] = gray / 255.0f;
938 }
939 break;
940 }
941
942 case QRhiTexture::RED_OR_ALPHA8:
943 case QRhiTexture::R8:
944 {
945 // R8 to R32F
946 buf.resize(N * 4);
947 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
948 auto dst = reinterpret_cast<float*>(buf.data());
949 for(int i = N - 1; i >= 0; i--)
950 {
951 dst[i] = src[i] / 255.0f;
952 }
953 break;
954 }
955
956 case QRhiTexture::R16:
957 {
958 // R16 to R32F
959 buf.resize(N * 4);
960 auto src = reinterpret_cast<const uint16_t*>(buf.constData());
961 auto dst = reinterpret_cast<float*>(buf.data());
962 for(int i = N - 1; i >= 0; i--)
963 {
964 dst[i] = src[i] / 65535.0f;
965 }
966 break;
967 }
968
969 case QRhiTexture::RGBA16F:
970 {
971 // RGBA16F to R32F
972 auto src = reinterpret_cast<const qfloat16*>(buf.constData());
973 auto dst = reinterpret_cast<float*>(buf.data());
974 for(int i = 0; i < N; i++)
975 {
976 dst[i] = src[i * 4 + 0] * 0.299f + src[i * 4 + 1] * 0.587f + src[i * 4 + 2] * 0.114f;
977 }
978 buf.resize(N * 4);
979 break;
980 }
981
982 case QRhiTexture::RGBA32F:
983 {
984 // RGBA32F to R32F
985 auto src = reinterpret_cast<const float*>(buf.constData());
986 auto dst = reinterpret_cast<float*>(buf.data());
987 for(int i = 0; i < N; i++)
988 {
989 // Grayscale from RGBA
990 dst[i] = src[i * 4 + 0] * 0.299f + src[i * 4 + 1] * 0.587f + src[i * 4 + 2] * 0.114f;
991 }
992 buf.resize(N * 4);
993 break;
994 }
995
996 case QRhiTexture::R16F:
997 {
998 // R16F to R32F
999 buf.resize(N * 4);
1000 auto src = reinterpret_cast<const qfloat16*>(buf.constData());
1001 auto dst = reinterpret_cast<float*>(buf.data());
1002 for(int i = N - 1; i >= 0; i--)
1003 {
1004 dst[i] = src[i];
1005 }
1006 break;
1007 }
1008
1009#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
1010 case QRhiTexture::R8UI:
1011 {
1012 // R8UI to R32F
1013 buf.resize(N * 4);
1014 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
1015 auto dst = reinterpret_cast<float*>(buf.data());
1016 for(int i = N - 1; i >= 0; i--)
1017 {
1018 dst[i] = src[i] / 255.0f;
1019 }
1020 break;
1021 }
1022
1023 case QRhiTexture::R32UI:
1024 {
1025 // R32UI to R32F
1026 auto src = reinterpret_cast<const uint32_t*>(buf.constData());
1027 auto dst = reinterpret_cast<float*>(buf.data());
1028 for(int i = 0; i < N; i++)
1029 {
1030 dst[i] = src[i] / 4294967295.0f;
1031 }
1032 break;
1033 }
1034
1035 case QRhiTexture::RGBA32UI:
1036 {
1037 // RGBA32UI to R32F
1038 auto src = reinterpret_cast<const uint32_t*>(buf.constData());
1039 auto dst = reinterpret_cast<float*>(buf.data());
1040 for(int i = 0; i < N; i++)
1041 {
1042 float gray = (src[i * 4 + 0] / 4294967295.0f) * 0.299f +
1043 (src[i * 4 + 1] / 4294967295.0f) * 0.587f +
1044 (src[i * 4 + 2] / 4294967295.0f) * 0.114f;
1045 dst[i] = gray;
1046 }
1047 buf.resize(N * 4);
1048 break;
1049 }
1050#endif
1051
1052 default:
1053 if(buf.size() != N * 4)
1054 buf.resize(N * 4);
1055 break;
1056 }
1057}
1058inline void toR32UI(QRhiTexture::Format in_format, QByteArray& buf, int width, int height)
1059{
1060 const int N = width * height;
1061 switch(in_format)
1062 {
1063#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
1064 case QRhiTexture::R32UI:
1065 break;
1066#endif
1067
1068 case QRhiTexture::RGBA8:
1069 {
1070 // RGBA8 to R32UI
1071 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
1072 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1073 for(int i = 0; i < N; i++)
1074 {
1075 uint32_t gray = (src[i * 4 + 0] * 299 + src[i * 4 + 1] * 587 + src[i * 4 + 2] * 114) / 1000;
1076 dst[i] = (gray * 4294967295UL) / 255;
1077 }
1078 break;
1079 }
1080
1081 case QRhiTexture::BGRA8:
1082 {
1083 // BGRA8 to R32UI
1084 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
1085 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1086 for(int i = 0; i < N; i++)
1087 {
1088 uint32_t gray = (src[i * 4 + 2] * 299 + src[i * 4 + 1] * 587 + src[i * 4 + 0] * 114) / 1000;
1089 dst[i] = (gray * 4294967295UL) / 255;
1090 }
1091 break;
1092 }
1093
1094 case QRhiTexture::RED_OR_ALPHA8:
1095 case QRhiTexture::R8:
1096 {
1097 // R8 to R32UI
1098 buf.resize(N * 4);
1099 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
1100 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1101 for(int i = N - 1; i >= 0; i--)
1102 {
1103 dst[i] = (src[i] * 4294967295UL) / 255;
1104 }
1105 break;
1106 }
1107
1108 case QRhiTexture::R16:
1109 {
1110 // R16 to R32UI
1111 buf.resize(N * 4);
1112 auto src = reinterpret_cast<const uint16_t*>(buf.constData());
1113 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1114 for(int i = N - 1; i >= 0; i--)
1115 {
1116 dst[i] = (uint64_t(src[i]) * 4294967295UL) / 65535;
1117 }
1118 break;
1119 }
1120
1121 case QRhiTexture::RGBA16F:
1122 {
1123 // RGBA16F to R32UI
1124 auto src = reinterpret_cast<const qfloat16*>(buf.constData());
1125 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1126 for(int i = 0; i < N; i++)
1127 {
1128 // Grayscale from RGBA
1129 float gray = src[i * 4 + 0] * 0.299f + src[i * 4 + 1] * 0.587f + src[i * 4 + 2] * 0.114f;
1130 dst[i] = qBound(0.0f, gray * 4294967295.0f, 4294967295.0f);
1131 }
1132 buf.resize(N * 4);
1133 break;
1134 }
1135
1136 case QRhiTexture::RGBA32F:
1137 {
1138 // RGBA32F to R32UI
1139 auto src = reinterpret_cast<const float*>(buf.constData());
1140 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1141 for(int i = 0; i < N; i++)
1142 {
1143 // Grayscale from RGBA
1144 float gray = src[i * 4 + 0] * 0.299f + src[i * 4 + 1] * 0.587f + src[i * 4 + 2] * 0.114f;
1145 dst[i] = qBound(0.0f, gray * 4294967295.0f, 4294967295.0f);
1146 }
1147 buf.resize(N * 4);
1148 break;
1149 }
1150
1151 case QRhiTexture::R16F:
1152 {
1153 // R16F to R32UI
1154 buf.resize(N * 4);
1155 auto src = reinterpret_cast<const qfloat16*>(buf.constData());
1156 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1157 for(int i = N - 1; i >= 0; i--)
1158 {
1159 float val = float(src[i]);
1160 dst[i] = qBound(0.0f, val * 4294967295.0f, 4294967295.0f);
1161 }
1162 break;
1163 }
1164
1165 case QRhiTexture::R32F:
1166 {
1167 // R32F to R32UI
1168 auto src = reinterpret_cast<const float*>(buf.constData());
1169 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1170 for(int i = 0; i < N; i++)
1171 {
1172 dst[i] = qBound(0.0f, src[i] * 4294967295.0f, 4294967295.0f);
1173 }
1174 break;
1175 }
1176
1177#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
1178 case QRhiTexture::R8UI:
1179 {
1180 // R8UI to R32UI
1181 buf.resize(N * 4);
1182 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
1183 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1184 for(int i = N - 1; i >= 0; i--)
1185 {
1186 dst[i] = (src[i] * 4294967295UL) / 255;
1187 }
1188 break;
1189 }
1190
1191 case QRhiTexture::RGBA32UI:
1192 {
1193 // RGBA32UI to R32U
1194 auto src = reinterpret_cast<const uint32_t*>(buf.constData());
1195 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1196 for(int i = 0; i < N; i++)
1197 {
1198 uint64_t gray = (uint64_t(src[i * 4 + 0]) * 299 + uint64_t(src[i * 4 + 1]) * 587 + uint64_t(src[i * 4 + 2]) * 114) / 1000;
1199 dst[i] = gray > 4294967295UL ? 4294967295UL : gray;
1200 }
1201 buf.resize(N * 4);
1202 break;
1203 }
1204#endif
1205
1206 default:
1207 if(buf.size() != N * 4)
1208 buf.resize(N * 4);
1209 break;
1210 }
1211}
1212inline void toRGBA32UI(QRhiTexture::Format in_format, QByteArray& buf, int width, int height)
1213{
1214 const int N = width * height;
1215 switch(in_format)
1216 {
1217#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
1218 case QRhiTexture::RGBA32UI:
1219 break;
1220#endif
1221
1222 case QRhiTexture::RGBA8:
1223 {
1224 // RGBA8 to RGBA32UI
1225 buf.resize(N * 16);
1226 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
1227 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1228 for(int i = N - 1; i >= 0; i--)
1229 {
1230 dst[i * 4 + 0] = (src[i * 4 + 0] * 4294967295UL) / 255;
1231 dst[i * 4 + 1] = (src[i * 4 + 1] * 4294967295UL) / 255;
1232 dst[i * 4 + 2] = (src[i * 4 + 2] * 4294967295UL) / 255;
1233 dst[i * 4 + 3] = (src[i * 4 + 3] * 4294967295UL) / 255;
1234 }
1235 break;
1236 }
1237
1238 case QRhiTexture::BGRA8:
1239 {
1240 // BGRA8 to RGBA32UI
1241 buf.resize(N * 16);
1242 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
1243 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1244 for(int i = N - 1; i >= 0; i--)
1245 {
1246 dst[i * 4 + 0] = (src[i * 4 + 2] * 4294967295UL) / 255; // B -> R
1247 dst[i * 4 + 1] = (src[i * 4 + 1] * 4294967295UL) / 255; // G -> G
1248 dst[i * 4 + 2] = (src[i * 4 + 0] * 4294967295UL) / 255; // R -> B
1249 dst[i * 4 + 3] = (src[i * 4 + 3] * 4294967295UL) / 255; // A -> A
1250 }
1251 break;
1252 }
1253
1254 case QRhiTexture::RED_OR_ALPHA8:
1255 case QRhiTexture::R8:
1256 {
1257 // R8 to RGBA32UI
1258 buf.resize(N * 16);
1259 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
1260 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1261 for(int i = N - 1; i >= 0; i--)
1262 {
1263 uint32_t gray = (src[i] * 4294967295UL) / 255;
1264 dst[i * 4 + 0] = gray;
1265 dst[i * 4 + 1] = gray;
1266 dst[i * 4 + 2] = gray;
1267 dst[i * 4 + 3] = 4294967295UL;
1268 }
1269 break;
1270 }
1271
1272 case QRhiTexture::R16:
1273 {
1274 // R16 to RGBA32UI
1275 buf.resize(N * 16);
1276 auto src = reinterpret_cast<const uint16_t*>(buf.constData());
1277 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1278 for(int i = N - 1; i >= 0; i--)
1279 {
1280 uint32_t gray = (uint64_t(src[i]) * 4294967295UL) / 65535;
1281 dst[i * 4 + 0] = gray;
1282 dst[i * 4 + 1] = gray;
1283 dst[i * 4 + 2] = gray;
1284 dst[i * 4 + 3] = 4294967295UL;
1285 }
1286 break;
1287 }
1288
1289 case QRhiTexture::RGBA16F:
1290 {
1291 // RGBA16F to RGBA32UI
1292 buf.resize(N * 16);
1293 auto src = reinterpret_cast<const qfloat16*>(buf.constData());
1294 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1295 for(int i = N - 1; i >= 0; i--)
1296 {
1297 dst[i * 4 + 0] = qBound(0.0f, float(src[i * 4 + 0]) * 4294967295.0f, 4294967295.0f);
1298 dst[i * 4 + 1] = qBound(0.0f, float(src[i * 4 + 1]) * 4294967295.0f, 4294967295.0f);
1299 dst[i * 4 + 2] = qBound(0.0f, float(src[i * 4 + 2]) * 4294967295.0f, 4294967295.0f);
1300 dst[i * 4 + 3] = qBound(0.0f, float(src[i * 4 + 3]) * 4294967295.0f, 4294967295.0f);
1301 }
1302 break;
1303 }
1304
1305 case QRhiTexture::RGBA32F:
1306 {
1307 // RGBA32F to RGBA32UI
1308 auto src = reinterpret_cast<const float*>(buf.constData());
1309 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1310 for(int i = 0; i < N; i++)
1311 {
1312 dst[i * 4 + 0] = qBound(0.0f, src[i * 4 + 0] * 4294967295.0f, 4294967295.0f);
1313 dst[i * 4 + 1] = qBound(0.0f, src[i * 4 + 1] * 4294967295.0f, 4294967295.0f);
1314 dst[i * 4 + 2] = qBound(0.0f, src[i * 4 + 2] * 4294967295.0f, 4294967295.0f);
1315 dst[i * 4 + 3] = qBound(0.0f, src[i * 4 + 3] * 4294967295.0f, 4294967295.0f);
1316 }
1317 break;
1318 }
1319
1320 case QRhiTexture::R16F:
1321 {
1322 // R16F to RGBA32UI
1323 buf.resize(N * 16);
1324 auto src = reinterpret_cast<const qfloat16*>(buf.constData());
1325 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1326 for(int i = N - 1; i >= 0; i--)
1327 {
1328 uint32_t gray = qBound(0.0f, float(src[i]) * 4294967295.0f, 4294967295.0f);
1329 dst[i * 4 + 0] = gray;
1330 dst[i * 4 + 1] = gray;
1331 dst[i * 4 + 2] = gray;
1332 dst[i * 4 + 3] = 4294967295UL;
1333 }
1334 break;
1335 }
1336
1337 case QRhiTexture::R32F:
1338 {
1339 // R32F to RGBA32UI
1340 buf.resize(N * 16);
1341 auto src = reinterpret_cast<const float*>(buf.constData());
1342 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1343 for(int i = N - 1; i >= 0; i--)
1344 {
1345 uint32_t gray = qBound(0.0f, src[i] * 4294967295.0f, 4294967295.0f);
1346 dst[i * 4 + 0] = gray;
1347 dst[i * 4 + 1] = gray;
1348 dst[i * 4 + 2] = gray;
1349 dst[i * 4 + 3] = 4294967295UL;
1350 }
1351 break;
1352 }
1353
1354#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
1355 case QRhiTexture::R8UI:
1356 {
1357 // R8UI to RGBA32UI
1358 buf.resize(N * 16);
1359 auto src = reinterpret_cast<const uint8_t*>(buf.constData());
1360 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1361 for(int i = N - 1; i >= 0; i--)
1362 {
1363 uint32_t gray = (src[i] * 4294967295UL) / 255;
1364 dst[i * 4 + 0] = gray;
1365 dst[i * 4 + 1] = gray;
1366 dst[i * 4 + 2] = gray;
1367 dst[i * 4 + 3] = 4294967295UL;
1368 }
1369 break;
1370 }
1371
1372 case QRhiTexture::R32UI:
1373 {
1374 // R32UI to RGBA32UI
1375 buf.resize(N * 16);
1376 auto src = reinterpret_cast<const uint32_t*>(buf.constData());
1377 auto dst = reinterpret_cast<uint32_t*>(buf.data());
1378 for(int i = N - 1; i >= 0; i--)
1379 {
1380 uint32_t gray = src[i];
1381 dst[i * 4 + 0] = gray;
1382 dst[i * 4 + 1] = gray;
1383 dst[i * 4 + 2] = gray;
1384 dst[i * 4 + 3] = 4294967295UL;
1385 }
1386 break;
1387 }
1388#endif
1389
1390 default:
1391 if(buf.size() < N * 16)
1392 buf.resize(N * 16);
1393 break;
1394 }
1395}
1396inline void convertTexture(QRhiTexture::Format out_format, QRhiTexture::Format in_format, QByteArray& buf, int width, int height)
1397{
1398 switch(out_format)
1399 {
1400 case QRhiTexture::BGRA8: // TODO
1401 case QRhiTexture::RGBA8:
1402 return toRGBA(in_format, buf, width, height);
1403
1404 case QRhiTexture::RED_OR_ALPHA8:
1405 case QRhiTexture::R8:
1406#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
1407 case QRhiTexture::R8UI:
1408#endif
1409 return toR8(in_format, buf, width, height);
1410
1411 case QRhiTexture::R16:
1412 return toR16(in_format, buf, width, height);
1413
1414 case QRhiTexture::RGBA32F:
1415 return toRGBA32F(in_format, buf, width, height);
1416
1417 case QRhiTexture::R32F:
1418 return toR32F(in_format, buf, width, height);
1419
1420#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
1421 case QRhiTexture::R32UI:
1422 return toR32UI(in_format, buf, width, height);
1423
1424 case QRhiTexture::RGBA32UI:
1425 return toRGBA32UI(in_format, buf, width, height);
1426#endif
1427
1428 case QRhiTexture::RG16:
1429 case QRhiTexture::RGBA16F:
1430 case QRhiTexture::RG8:
1431 case QRhiTexture::R16F:
1432#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
1433 case QRhiTexture::RGB10A2:
1434#endif
1435#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
1436 case QRhiTexture::RG32UI:
1437#endif
1438 case QRhiTexture::D16:
1439 case QRhiTexture::D24:
1440 case QRhiTexture::D24S8:
1441 case QRhiTexture::D32F:
1442#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
1443 case QRhiTexture::D32FS8:
1444#endif
1445 case QRhiTexture::UnknownFormat:
1446 case QRhiTexture::BC1:
1447 case QRhiTexture::BC2:
1448 case QRhiTexture::BC3:
1449 case QRhiTexture::BC4:
1450 case QRhiTexture::BC5:
1451 case QRhiTexture::BC6H:
1452 case QRhiTexture::BC7:
1453 case QRhiTexture::ETC2_RGB8:
1454 case QRhiTexture::ETC2_RGB8A1:
1455 case QRhiTexture::ETC2_RGBA8:
1456 case QRhiTexture::ASTC_4x4:
1457 case QRhiTexture::ASTC_5x4:
1458 case QRhiTexture::ASTC_5x5:
1459 case QRhiTexture::ASTC_6x5:
1460 case QRhiTexture::ASTC_6x6:
1461 case QRhiTexture::ASTC_8x5:
1462 case QRhiTexture::ASTC_8x6:
1463 case QRhiTexture::ASTC_8x8:
1464 case QRhiTexture::ASTC_10x5:
1465 case QRhiTexture::ASTC_10x6:
1466 case QRhiTexture::ASTC_10x8:
1467 case QRhiTexture::ASTC_10x10:
1468 case QRhiTexture::ASTC_12x10:
1469 case QRhiTexture::ASTC_12x12:
1470 break;
1471 }
1472}
1473}
1474
1475namespace oscr
1476{
1477
1478inline void
1479inplaceMirror(unsigned char* bytes, int width, int height, int bytes_per_pixel)
1480{
1481 if(width < 1 || height <= 1)
1482 return;
1483 const size_t row_size = width * bytes_per_pixel;
1484
1485 auto temp_row = (unsigned char*)alloca(row_size);
1486 auto top = bytes;
1487 auto bottom = bytes + (height - 1) * row_size;
1488
1489 while(top < bottom)
1490 {
1491 memcpy(temp_row, top, row_size);
1492 memcpy(top, bottom, row_size);
1493 memcpy(bottom, temp_row, row_size);
1494
1495 top += row_size;
1496 bottom -= row_size;
1497 }
1498}
1499
1500template <avnd::cpu_texture Tex>
1501void loadInputTexture(QRhi& rhi, auto& m_readbacks, Tex& cpu_tex, int k)
1502{
1503 auto& rb = m_readbacks[k];
1504 auto& buf = rb.data;
1505 qsizetype bytesize{};
1506 if_possible(bytesize = cpu_tex.bytesize())
1507 else if_possible(bytesize = cpu_tex.bytesize)
1508 else return;
1509
1510 if(buf.size() < bytesize)
1511 {
1512 cpu_tex.bytes = nullptr;
1513 }
1514 else
1515 {
1516 // FIXME ARGB needs special handling too
1517 if constexpr(requires { std::string_view{Tex::format()}; })
1518 {
1519 constexpr std::string_view fmt = Tex::format();
1520 if(fmt == "rgb") {
1521 gpp::qrhi::toRGB(rb.format, buf, rb.pixelSize.width(), rb.pixelSize.height());
1522 }
1523 else
1524 {
1525 const auto dstFormat = gpp::qrhi::textureFormat(cpu_tex);
1526 gpp::qrhi::convertTexture(dstFormat, rb.format, buf, rb.pixelSize.width(), rb.pixelSize.height());
1527 }
1528 }
1529 else if constexpr(requires { Tex::RGB; })
1530 {
1531 if constexpr(avnd::cpu_dynamic_format_texture<Tex>){
1532 if(cpu_tex.format == Tex::RGB)
1533 gpp::qrhi::toRGB(rb.format, buf, rb.pixelSize.width(), rb.pixelSize.height());
1534 else
1535 {
1536 const auto dstFormat = gpp::qrhi::textureFormat(cpu_tex);
1537 gpp::qrhi::convertTexture(dstFormat, rb.format, buf, rb.pixelSize.width(), rb.pixelSize.height());
1538 }
1539 }
1540 else
1541 {
1542 gpp::qrhi::toRGB(rb.format, buf, rb.pixelSize.width(), rb.pixelSize.height());
1543 }
1544 }
1545 else
1546 {
1547 const auto dstFormat = gpp::qrhi::textureFormat(cpu_tex);
1548 gpp::qrhi::convertTexture(dstFormat, rb.format, buf, rb.pixelSize.width(), rb.pixelSize.height());
1549 }
1550
1551 using components_type = std::decay_t<decltype(cpu_tex.bytes)>;
1552 cpu_tex.bytes = reinterpret_cast<components_type>(buf.data());
1553
1554 if(rhi.isYUpInNDC())
1555 if(cpu_tex.width * cpu_tex.height > 0)
1556 inplaceMirror(
1557 reinterpret_cast<unsigned char*>(cpu_tex.bytes), cpu_tex.width,
1558 cpu_tex.height, cpu_tex.bytes_per_pixel);
1559
1560 cpu_tex.changed = true;
1561 }
1562}
1563}
Definition Factories.hpp:19