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