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
3033namespace filament {
3134namespace 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