Skip to content

Commit 9a90c8e

Browse files
committed
backend: enhance data reshaper
- add half float as source type - gray-scaled output when src-channel=1 and dest-channel=3 or 4
1 parent 58f6d77 commit 9a90c8e

File tree

1 file changed

+145
-57
lines changed

1 file changed

+145
-57
lines changed

filament/backend/src/DataReshaper.h

Lines changed: 145 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@
1919

2020
#include <backend/PixelBufferDescriptor.h>
2121

22+
#include <cstdint>
2223
#include <cstring>
2324
#include <stddef.h>
2425
#include <stdint.h>
2526

2627
#include <math/scalar.h>
28+
#include <math/half.h>
2729

2830
#include <utils/debug.h>
31+
#include <utils/Logger.h>
2932

3033
namespace filament {
3134
namespace backend {
@@ -76,39 +79,55 @@ class DataReshaper {
7679
}
7780
}
7881

79-
// Converts a n-channel image of UBYTE, INT, UINT, or FLOAT to a different type.
82+
// Converts a n-channel image of UBYTE, INT, UINT, HALF, or FLOAT to a different type.
8083
template<typename dstComponentType, typename srcComponentType>
8184
static void reshapeImage(uint8_t* UTILS_RESTRICT dest, const uint8_t* UTILS_RESTRICT src,
82-
size_t srcBytesPerRow,
83-
size_t srcChannelCount,
84-
size_t dstRowOffset, size_t dstColumnOffset,
85-
size_t dstBytesPerRow, size_t dstChannelCount,
86-
size_t width, size_t height, bool swizzle) {
87-
// TODO: there's a fast-path where memcpy will work but currently not being taken advantage
88-
// of.
85+
size_t srcBytesPerRow, size_t srcChannelCount, size_t dstRowOffset,
86+
size_t dstColumnOffset, size_t dstBytesPerRow, size_t dstChannelCount, size_t width,
87+
size_t height, bool swizzle) {
88+
89+
static_assert(!std::is_same_v<dstComponentType, math::half>);
8990

9091
const dstComponentType dstMaxValue = getMaxValue<dstComponentType>();
9192
const srcComponentType srcMaxValue = getMaxValue<srcComponentType>();
93+
94+
double const mFactor = dstMaxValue / ((double) srcMaxValue);
95+
9296
const size_t minChannelCount = math::min(srcChannelCount, dstChannelCount);
9397
assert_invariant(minChannelCount <= 4);
9498
UTILS_ASSUME(minChannelCount <= 4);
9599
dest += (dstRowOffset * dstBytesPerRow);
96100
const int inds[4] = { swizzle ? 2 : 0, 1, swizzle ? 0 : 2, 3 };
101+
97102
for (size_t row = 0; row < height; ++row) {
98103
const srcComponentType* in = (const srcComponentType*) src;
99-
dstComponentType* out = (dstComponentType*)dest + (dstColumnOffset * dstChannelCount);
104+
dstComponentType* out = (dstComponentType*) dest + (dstColumnOffset * dstChannelCount);
100105
for (size_t column = 0; column < width; ++column) {
101106
for (size_t channel = 0; channel < minChannelCount; ++channel) {
102107
if constexpr (std::is_same_v<dstComponentType, srcComponentType>) {
103108
out[channel] = in[inds[channel]];
104109
} else {
105-
// FIXME: beware of overflows in the multiply
106-
// FIXME: probably not correct for _INTEGER src/dst
107-
out[channel] = in[inds[channel]] * dstMaxValue / srcMaxValue;
110+
// convert to double then clamp and cast to dst type.
111+
out[channel] = static_cast<dstComponentType>(std::clamp(
112+
in[inds[channel]] * mFactor, 0.0,
113+
static_cast<double>(std::numeric_limits<dstComponentType>::max())));
108114
}
109115
}
110-
for (size_t channel = srcChannelCount; channel < dstChannelCount; ++channel) {
111-
out[channel] = dstMaxValue;
116+
if (srcChannelCount == 1 && (dstChannelCount == 3 || dstChannelCount == 4)) {
117+
// For the special case of src-channel-count=1, dst-channel-count=3/4, we assume
118+
// the output should be a grayscale image with alpha=1 and the gray value is set
119+
// to the src value. This is useful for producing a grayscale image from a depth
120+
// map.
121+
for (size_t channel = 1; channel < 3; ++channel) {
122+
out[channel] = out[0];
123+
}
124+
if (dstChannelCount == 4) {
125+
out[3] = dstMaxValue;
126+
}
127+
} else {
128+
for (size_t channel = srcChannelCount; channel < dstChannelCount; ++channel) {
129+
out[channel] = dstMaxValue;
130+
}
112131
}
113132
in += srcChannelCount;
114133
out += dstChannelCount;
@@ -120,25 +139,42 @@ class DataReshaper {
120139

121140
// Converts a n-channel image of UBYTE, INT, UINT, or FLOAT to a different type.
122141
static bool reshapeImage(PixelBufferDescriptor* UTILS_RESTRICT dst, PixelDataType srcType,
123-
uint32_t srcChannelCount, const uint8_t* UTILS_RESTRICT srcBytes, int srcBytesPerRow,
142+
uint32_t srcChannelCount, const uint8_t* UTILS_RESTRICT srcBytes, int srcBytesPerRow,
124143
int width, int height, bool swizzle) {
125144
size_t dstChannelCount;
126145
switch (dst->format) {
127-
case PixelDataFormat::R_INTEGER: dstChannelCount = 1; break;
128-
case PixelDataFormat::RG_INTEGER: dstChannelCount = 2; break;
129-
case PixelDataFormat::RGB_INTEGER: dstChannelCount = 3; break;
130-
case PixelDataFormat::RGBA_INTEGER: dstChannelCount = 4; break;
131-
case PixelDataFormat::R: dstChannelCount = 1; break;
132-
case PixelDataFormat::RG: dstChannelCount = 2; break;
133-
case PixelDataFormat::RGB: dstChannelCount = 3; break;
134-
case PixelDataFormat::RGBA: dstChannelCount = 4; break;
135-
default: return false;
146+
case PixelDataFormat::R_INTEGER:
147+
dstChannelCount = 1;
148+
break;
149+
case PixelDataFormat::RG_INTEGER:
150+
dstChannelCount = 2;
151+
break;
152+
case PixelDataFormat::RGB_INTEGER:
153+
dstChannelCount = 3;
154+
break;
155+
case PixelDataFormat::RGBA_INTEGER:
156+
dstChannelCount = 4;
157+
break;
158+
case PixelDataFormat::R:
159+
dstChannelCount = 1;
160+
break;
161+
case PixelDataFormat::RG:
162+
dstChannelCount = 2;
163+
break;
164+
case PixelDataFormat::RGB:
165+
dstChannelCount = 3;
166+
break;
167+
case PixelDataFormat::RGBA:
168+
dstChannelCount = 4;
169+
break;
170+
default:
171+
LOG(ERROR) << "DataReshaper: unsupported dst->format: " << (int) dst->format;
172+
return false;
136173
}
137174
void (*reshaper)(uint8_t* dest, const uint8_t* src, size_t srcBytesPerRow,
138-
size_t srcChannelCount,
139-
size_t srcRowOffset, size_t srcColumnOffset,
140-
size_t dstBytesPerRow, size_t dstChannelCount,
141-
size_t width, size_t height, bool swizzle) = nullptr;
175+
size_t srcChannelCount, size_t srcRowOffset, size_t srcColumnOffset,
176+
size_t dstBytesPerRow, size_t dstChannelCount, size_t width, size_t height,
177+
bool swizzle) = nullptr;
142178
constexpr auto UBYTE = PixelDataType::UBYTE;
143179
constexpr auto FLOAT = PixelDataType::FLOAT;
144180
constexpr auto UINT = PixelDataType::UINT;
@@ -155,63 +191,115 @@ class DataReshaper {
155191
reshaper = copyImage;
156192
}
157193
break;
158-
case FLOAT: reshaper = reshapeImage<uint8_t, float>; break;
159-
case INT: reshaper = reshapeImage<uint8_t, int32_t>; break;
160-
case UINT: reshaper = reshapeImage<uint8_t, uint32_t>; break;
161-
default: return false;
194+
case FLOAT:
195+
reshaper = reshapeImage<uint8_t, float>;
196+
break;
197+
case INT:
198+
reshaper = reshapeImage<uint8_t, int32_t>;
199+
break;
200+
case UINT:
201+
reshaper = reshapeImage<uint8_t, uint32_t>;
202+
break;
203+
case HALF:
204+
reshaper = reshapeImage<uint8_t, math::half>;
205+
break;
206+
default:
207+
LOG(ERROR) << "DataReshaper: UBYTE dst, unsupported srcType: "
208+
<< (int) srcType;
209+
return false;
162210
}
163211
break;
164212
case FLOAT:
165213
switch (srcType) {
166-
case UBYTE: reshaper = reshapeImage<float, uint8_t>; break;
167-
case FLOAT: reshaper = reshapeImage<float, float>; break;
168-
case INT: reshaper = reshapeImage<float, int32_t>; break;
169-
case UINT: reshaper = reshapeImage<float, uint32_t>; break;
170-
default: return false;
214+
case UBYTE:
215+
reshaper = reshapeImage<float, uint8_t>;
216+
break;
217+
case FLOAT:
218+
reshaper = reshapeImage<float, float>;
219+
break;
220+
case INT:
221+
reshaper = reshapeImage<float, int32_t>;
222+
break;
223+
case UINT:
224+
reshaper = reshapeImage<float, uint32_t>;
225+
break;
226+
default:
227+
LOG(ERROR) << "DataReshaper: FLOAT dst, unsupported srcType: "
228+
<< (int) srcType;
229+
return false;
171230
}
172231
break;
173232
case INT:
174233
switch (srcType) {
175-
case UBYTE: reshaper = reshapeImage<int32_t, uint8_t>; break;
176-
case FLOAT: reshaper = reshapeImage<int32_t, float>; break;
177-
case INT: reshaper = reshapeImage<int32_t, int32_t>; break;
178-
case UINT: reshaper = reshapeImage<int32_t, uint32_t>; break;
179-
default: return false;
234+
case UBYTE:
235+
reshaper = reshapeImage<int32_t, uint8_t>;
236+
break;
237+
case FLOAT:
238+
reshaper = reshapeImage<int32_t, float>;
239+
break;
240+
case INT:
241+
reshaper = reshapeImage<int32_t, int32_t>;
242+
break;
243+
case UINT:
244+
reshaper = reshapeImage<int32_t, uint32_t>;
245+
break;
246+
default:
247+
LOG(ERROR)
248+
<< "DataReshaper: INT dst, unsupported srcType: " << (int) srcType;
249+
return false;
180250
}
181251
break;
182252
case UINT:
183253
switch (srcType) {
184-
case UBYTE: reshaper = reshapeImage<uint32_t, uint8_t>; break;
185-
case FLOAT: reshaper = reshapeImage<uint32_t, float>; break;
186-
case INT: reshaper = reshapeImage<uint32_t, int32_t>; break;
187-
case UINT: reshaper = reshapeImage<uint32_t, uint32_t>; break;
188-
default: return false;
254+
case UBYTE:
255+
reshaper = reshapeImage<uint32_t, uint8_t>;
256+
break;
257+
case FLOAT:
258+
reshaper = reshapeImage<uint32_t, float>;
259+
break;
260+
case INT:
261+
reshaper = reshapeImage<uint32_t, int32_t>;
262+
break;
263+
case UINT:
264+
reshaper = reshapeImage<uint32_t, uint32_t>;
265+
break;
266+
default:
267+
LOG(ERROR)
268+
<< "DataReshaper: UINT dst, unsupported srcType: " << (int) srcType;
269+
return false;
189270
}
190271
break;
191272
case HALF:
192273
switch (srcType) {
193-
case HALF: reshaper = copyImage; break;
194-
default: return false;
274+
case HALF:
275+
reshaper = copyImage;
276+
break;
277+
default:
278+
LOG(ERROR)
279+
<< "DataReshaper: HALF dst, unsupported srcType: " << (int) srcType;
280+
return false;
195281
}
196282
break;
197283
default:
284+
LOG(ERROR) << "DataReshaper: unsupported dst->type: " << (int) dst->type;
198285
return false;
199286
}
200287
uint8_t* dstBytes = (uint8_t*) dst->buffer;
201288
const int dstBytesPerRow = PixelBufferDescriptor::computeDataSize(dst->format, dst->type,
202289
dst->stride ? dst->stride : width, 1, dst->alignment);
203-
reshaper(dstBytes, srcBytes, srcBytesPerRow, srcChannelCount,
204-
dst->top, dst->left, dstBytesPerRow,
205-
dstChannelCount, width, height, swizzle);
290+
reshaper(dstBytes, srcBytes, srcBytesPerRow, srcChannelCount, dst->top, dst->left,
291+
dstBytesPerRow, dstChannelCount, width, height, swizzle);
292+
206293
return true;
207294
}
208295
};
209296

210-
template<> inline float getMaxValue() { return 1.0f; }
211-
template<> inline int32_t getMaxValue() { return 0x7fffffff; }
212-
template<> inline uint32_t getMaxValue() { return 0xffffffff; }
213-
template<> inline uint16_t getMaxValue() { return 0x3c00; } // 0x3c00 is 1.0 in half-float.
214-
template<> inline uint8_t getMaxValue() { return 0xff; }
297+
template<> inline constexpr float getMaxValue() { return 1.0f; }
298+
template<> inline constexpr int32_t getMaxValue() { return 0x7fffffff; }
299+
template<> inline constexpr uint32_t getMaxValue() { return 0xffffffff; }
300+
template<> inline constexpr uint16_t getMaxValue() { return 0x3c00; } // 0x3c00 is 1.0 in half-float.
301+
template<> inline constexpr uint8_t getMaxValue() { return 0xff; }
302+
template<> inline math::half getMaxValue() { return math::half(1.0f); }
215303

216304
} // namespace backend
217305
} // namespace filament

0 commit comments

Comments
 (0)