1919
2020#include < backend/PixelBufferDescriptor.h>
2121
22- #include < cstring>
23- #include < stddef.h>
24- #include < stdint.h>
25-
2622#include < math/scalar.h>
23+ #include < math/half.h>
2724
2825#include < utils/debug.h>
26+ #include < utils/Logger.h>
27+
28+ #include < cstdint>
29+ #include < cstring>
30+ #include < stddef.h>
31+ #include < stdint.h>
2932
3033namespace filament {
3134namespace backend {
3235
36+ namespace {
37+
3338// Provides an alpha value when expanding 3-channel images to 4-channel.
3439// Also used as a normalization scale when converting between numeric types.
3540template <typename componentType> inline componentType getMaxValue ();
3641
42+ template <> inline constexpr float getMaxValue () { return 1 .0f ; }
43+ template <> inline constexpr int32_t getMaxValue () { return 0x7fffffff ; }
44+ template <> inline constexpr uint32_t getMaxValue () { return 0xffffffff ; }
45+ template <> inline constexpr uint16_t getMaxValue () { return 0x3c00 ; } // 0x3c00 is 1.0 in half-float.
46+ template <> inline constexpr uint8_t getMaxValue () { return 0xff ; }
47+ template <> inline math::half getMaxValue () { return math::half (1 .0f ); }
48+
49+ template <typename srcComponentType, typename dstComponentType, uint8_t srcChannelCount,
50+ uint8_t dstChannelCount>
51+ void reshapeImageKernel (uint8_t * UTILS_RESTRICT dest, const uint8_t * UTILS_RESTRICT src,
52+ size_t srcBytesPerRow, size_t dstRowOffset, size_t dstColumnOffset, size_t dstBytesPerRow,
53+ size_t width, size_t height, bool swizzle) {
54+ constexpr size_t minChannelCount = math::min (srcChannelCount, dstChannelCount);
55+ const dstComponentType dstMaxValue = getMaxValue<dstComponentType>();
56+ const srcComponentType srcMaxValue = getMaxValue<srcComponentType>();
57+ double const mFactor = dstMaxValue / ((double ) srcMaxValue);
58+ assert_invariant (minChannelCount <= 4 );
59+ UTILS_ASSUME (minChannelCount <= 4 );
60+ dest += (dstRowOffset * dstBytesPerRow);
61+
62+ const int inds[4 ] = { swizzle ? 2 : 0 , 1 , swizzle ? 0 : 2 , 3 };
63+ for (size_t row = 0 ; row < height; ++row) {
64+ const srcComponentType* in = (const srcComponentType*) src;
65+ dstComponentType* out = (dstComponentType*) dest + (dstColumnOffset * dstChannelCount);
66+ for (size_t column = 0 ; column < width; ++column) {
67+ for (size_t channel = 0 ; channel < minChannelCount; ++channel) {
68+ if constexpr (std::is_same_v<dstComponentType, srcComponentType>) {
69+ out[channel] = in[inds[channel]];
70+ } else {
71+ // convert to double then clamp and cast to dst type.
72+ out[channel] = static_cast <dstComponentType>(std::clamp (
73+ in[inds[channel]] * mFactor , 0.0 ,
74+ static_cast <double >(std::numeric_limits<dstComponentType>::max ())));
75+ }
76+ }
77+ if constexpr (srcChannelCount == 1 && (dstChannelCount == 3 || dstChannelCount == 4 )) {
78+ // For the special case of src-channel-count=1, dst-channel-count=3/4, we assume
79+ // the output should be a grayscale image with alpha=1 and the gray value is set
80+ // to the src value. This is useful for producing a grayscale image from a depth
81+ // map.
82+ for (size_t channel = 1 ; channel < 3 ; ++channel) {
83+ out[channel] = out[0 ];
84+ }
85+ if constexpr (dstChannelCount == 4 ) {
86+ out[3 ] = dstMaxValue;
87+ }
88+ } else {
89+ for (size_t channel = srcChannelCount; channel < dstChannelCount; ++channel) {
90+ out[channel] = dstMaxValue;
91+ }
92+ }
93+ in += srcChannelCount;
94+ out += dstChannelCount;
95+ }
96+ src += srcBytesPerRow;
97+ dest += dstBytesPerRow;
98+ }
99+ }
100+
101+ // Converts a n-channel image of UBYTE, INT, UINT, HALF, or FLOAT to a different type.
102+ template <typename dstComponentType, typename srcComponentType>
103+ static void reshapeImageImpl (uint8_t * UTILS_RESTRICT dest, const uint8_t * UTILS_RESTRICT src,
104+ size_t srcBytesPerRow, size_t srcChannelCount, size_t dstRowOffset, size_t dstColumnOffset,
105+ size_t dstBytesPerRow, size_t dstChannelCount, size_t width, size_t height, bool swizzle) {
106+
107+ static_assert (!std::is_same_v<dstComponentType, math::half>);
108+
109+ void (*impl)(uint8_t * dest, const uint8_t * src, size_t srcBytesPerRow, size_t srcRowOffset,
110+ size_t srcColumnOffset, size_t dstBytesPerRow, size_t width, size_t height,
111+ bool swizzle) = nullptr ;
112+
113+ auto channelCountError = [srcChannelCount, dstChannelCount]() {
114+ LOG (ERROR) << " DataReshaper: src/dst channel count not supported : " << srcChannelCount
115+ << " /" << dstChannelCount;
116+ };
117+
118+ if (srcChannelCount == 1 ) {
119+ switch (dstChannelCount) {
120+ case 1 : impl = reshapeImageKernel<srcComponentType, dstComponentType, 1 , 1 >; break ;
121+ case 2 : impl = reshapeImageKernel<srcComponentType, dstComponentType, 1 , 2 >; break ;
122+ case 3 : impl = reshapeImageKernel<srcComponentType, dstComponentType, 1 , 3 >; break ;
123+ case 4 : impl = reshapeImageKernel<srcComponentType, dstComponentType, 1 , 4 >; break ;
124+ default : channelCountError (); break ;
125+ }
126+ } else if (srcChannelCount == 2 ) {
127+ switch (dstChannelCount) {
128+ case 1 : impl = reshapeImageKernel<srcComponentType, dstComponentType, 2 , 1 >; break ;
129+ case 2 : impl = reshapeImageKernel<srcComponentType, dstComponentType, 2 , 2 >; break ;
130+ case 3 : impl = reshapeImageKernel<srcComponentType, dstComponentType, 2 , 3 >; break ;
131+ case 4 : impl = reshapeImageKernel<srcComponentType, dstComponentType, 2 , 4 >; break ;
132+ default : channelCountError (); break ;
133+ }
134+ } else if (srcChannelCount == 3 ) {
135+ switch (dstChannelCount) {
136+ case 1 : impl = reshapeImageKernel<srcComponentType, dstComponentType, 3 , 1 >; break ;
137+ case 2 : impl = reshapeImageKernel<srcComponentType, dstComponentType, 3 , 2 >; break ;
138+ case 3 : impl = reshapeImageKernel<srcComponentType, dstComponentType, 3 , 3 >; break ;
139+ case 4 : impl = reshapeImageKernel<srcComponentType, dstComponentType, 3 , 4 >; break ;
140+ default : channelCountError (); break ;
141+ }
142+ } else if (srcChannelCount == 4 ) {
143+ switch (dstChannelCount) {
144+ case 1 : impl = reshapeImageKernel<srcComponentType, dstComponentType, 4 , 1 >; break ;
145+ case 2 : impl = reshapeImageKernel<srcComponentType, dstComponentType, 4 , 2 >; break ;
146+ case 3 : impl = reshapeImageKernel<srcComponentType, dstComponentType, 4 , 3 >; break ;
147+ case 4 : impl = reshapeImageKernel<srcComponentType, dstComponentType, 4 , 4 >; break ;
148+ default : channelCountError (); break ;
149+ }
150+ } else {
151+ channelCountError ();
152+ }
153+
154+ if (impl) {
155+ impl (dest, src, srcBytesPerRow, dstRowOffset, dstColumnOffset, dstBytesPerRow, width,
156+ height, swizzle);
157+ }
158+ }
159+
160+ } // anonymous namespace
161+
37162class DataReshaper {
38163public:
39164
@@ -76,51 +201,9 @@ class DataReshaper {
76201 }
77202 }
78203
79- // Converts a n-channel image of UBYTE, INT, UINT, or FLOAT to a different type.
80- template <typename dstComponentType, typename srcComponentType>
81- 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.
89-
90- const dstComponentType dstMaxValue = getMaxValue<dstComponentType>();
91- const srcComponentType srcMaxValue = getMaxValue<srcComponentType>();
92- const size_t minChannelCount = math::min (srcChannelCount, dstChannelCount);
93- assert_invariant (minChannelCount <= 4 );
94- UTILS_ASSUME (minChannelCount <= 4 );
95- dest += (dstRowOffset * dstBytesPerRow);
96- const int inds[4 ] = { swizzle ? 2 : 0 , 1 , swizzle ? 0 : 2 , 3 };
97- for (size_t row = 0 ; row < height; ++row) {
98- const srcComponentType* in = (const srcComponentType*) src;
99- dstComponentType* out = (dstComponentType*)dest + (dstColumnOffset * dstChannelCount);
100- for (size_t column = 0 ; column < width; ++column) {
101- for (size_t channel = 0 ; channel < minChannelCount; ++channel) {
102- if constexpr (std::is_same_v<dstComponentType, srcComponentType>) {
103- out[channel] = in[inds[channel]];
104- } 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;
108- }
109- }
110- for (size_t channel = srcChannelCount; channel < dstChannelCount; ++channel) {
111- out[channel] = dstMaxValue;
112- }
113- in += srcChannelCount;
114- out += dstChannelCount;
115- }
116- src += srcBytesPerRow;
117- dest += dstBytesPerRow;
118- }
119- }
120-
121204 // Converts a n-channel image of UBYTE, INT, UINT, or FLOAT to a different type.
122205 static bool reshapeImage (PixelBufferDescriptor* UTILS_RESTRICT dst, PixelDataType srcType,
123- uint32_t srcChannelCount, const uint8_t * UTILS_RESTRICT srcBytes, int srcBytesPerRow,
206+ uint32_t srcChannelCount, const uint8_t * UTILS_RESTRICT srcBytes, int srcBytesPerRow,
124207 int width, int height, bool swizzle) {
125208 size_t dstChannelCount;
126209 switch (dst->format ) {
@@ -132,13 +215,14 @@ class DataReshaper {
132215 case PixelDataFormat::RG: dstChannelCount = 2 ; break ;
133216 case PixelDataFormat::RGB: dstChannelCount = 3 ; break ;
134217 case PixelDataFormat::RGBA: dstChannelCount = 4 ; break ;
135- default : return false ;
218+ default :
219+ LOG (ERROR) << " DataReshaper: unsupported dst->format: " << (int ) dst->format ;
220+ return false ;
136221 }
137222 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 ;
223+ size_t srcChannelCount, size_t srcRowOffset, size_t srcColumnOffset,
224+ size_t dstBytesPerRow, size_t dstChannelCount, size_t width, size_t height,
225+ bool swizzle) = nullptr ;
142226 constexpr auto UBYTE = PixelDataType::UBYTE;
143227 constexpr auto FLOAT = PixelDataType::FLOAT;
144228 constexpr auto UINT = PixelDataType::UINT;
@@ -148,71 +232,84 @@ class DataReshaper {
148232 case UBYTE:
149233 switch (srcType) {
150234 case UBYTE:
151- reshaper = reshapeImage <uint8_t , uint8_t >;
235+ reshaper = reshapeImageImpl <uint8_t , uint8_t >;
152236 if (dst->format == PixelDataFormat::RGBA &&
153237 dstChannelCount == srcChannelCount && !swizzle && dst->top == 0 &&
154238 dst->left == 0 ) {
155239 reshaper = copyImage;
156240 }
157241 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 ;
242+ case FLOAT: reshaper = reshapeImageImpl<uint8_t , float >; break ;
243+ case INT: reshaper = reshapeImageImpl<uint8_t , int32_t >; break ;
244+ case UINT: reshaper = reshapeImageImpl<uint8_t , uint32_t >; break ;
245+ case HALF: reshaper = reshapeImageImpl<uint8_t , math::half>; break ;
246+ default :
247+ LOG (ERROR) << " DataReshaper: UBYTE dst, unsupported srcType: "
248+ << (int ) srcType;
249+ return false ;
162250 }
163251 break ;
164252 case FLOAT:
165253 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 ;
254+ case UBYTE: reshaper = reshapeImageImpl<float , uint8_t >; break ;
255+ case FLOAT: reshaper = reshapeImageImpl<float , float >; break ;
256+ case INT: reshaper = reshapeImageImpl<float , int32_t >; break ;
257+ case UINT: reshaper = reshapeImageImpl<float , uint32_t >; break ;
258+ default :
259+ LOG (ERROR) << " DataReshaper: FLOAT dst, unsupported srcType: "
260+ << (int ) srcType;
261+ return false ;
171262 }
172263 break ;
173264 case INT:
174265 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 ;
266+ case UBYTE: reshaper = reshapeImageImpl<int32_t , uint8_t >; break ;
267+ case FLOAT: reshaper = reshapeImageImpl<int32_t , float >; break ;
268+ case INT: reshaper = reshapeImageImpl<int32_t , int32_t >; break ;
269+ case UINT: reshaper = reshapeImageImpl<int32_t , uint32_t >; break ;
270+ default :
271+ LOG (ERROR)
272+ << " DataReshaper: INT dst, unsupported srcType: " << (int ) srcType;
273+ return false ;
180274 }
181275 break ;
182276 case UINT:
183277 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 ;
278+ case UBYTE: reshaper = reshapeImageImpl<uint32_t , uint8_t >; break ;
279+ case FLOAT: reshaper = reshapeImageImpl<uint32_t , float >; break ;
280+ case INT: reshaper = reshapeImageImpl<uint32_t , int32_t >; break ;
281+ case UINT: reshaper = reshapeImageImpl<uint32_t , uint32_t >; break ;
282+ default :
283+ LOG (ERROR)
284+ << " DataReshaper: UINT dst, unsupported srcType: " << (int ) srcType;
285+ return false ;
189286 }
190287 break ;
191288 case HALF:
192289 switch (srcType) {
193- case HALF: reshaper = copyImage; break ;
194- default : return false ;
290+ case HALF:
291+ reshaper = copyImage;
292+ break ;
293+ default :
294+ LOG (ERROR)
295+ << " DataReshaper: HALF dst, unsupported srcType: " << (int ) srcType;
296+ return false ;
195297 }
196298 break ;
197299 default :
300+ LOG (ERROR) << " DataReshaper: unsupported dst->type: " << (int ) dst->type ;
198301 return false ;
199302 }
200303 uint8_t * dstBytes = (uint8_t *) dst->buffer ;
201304 const int dstBytesPerRow = PixelBufferDescriptor::computeDataSize (dst->format , dst->type ,
202305 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);
306+ reshaper (dstBytes, srcBytes, srcBytesPerRow, srcChannelCount, dst-> top , dst-> left ,
307+ dstBytesPerRow, dstChannelCount, width, height, swizzle);
308+
206309 return true ;
207310 }
208311};
209312
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 ; }
215-
216313} // namespace backend
217314} // namespace filament
218315
0 commit comments