|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- ### what is packing and why
-
- packing is the form of storing multiple short-sized values as one long-sized value.
-
- element packing is well mapped with the underlying simd register, which usually use one very wide register to store different types of values.
-
- |C|elemsize|elempack|
- |---|---|---|
- |double|8|1|
- |float|4|1|
- |int|4|1|
- |short|2|1|
- |signed char|1|1|
-
- |arm neon|elemsize|elempack|
- |---|---|---|
- |float64x2_t|16|2|
- |float32x4_t|16|4|
- |int32x4_t|16|4|
- |float16x4_t|8|4|
- |int8x8_t|8|8|
-
- Though the real count of values doubles when elempack is two, the wide-sized value is still treated as one value in the view of Mat structure. For example, we want to store 40 float values in Mat object, if elempack 1 is used, Mat width is then 40, while 10 if elempack 4 is used.
-
- |dims|w|h|c|cstep|elemsize|elempack|
- |---|---|---|---|---|---|---|
- |1|40|1|1|40|4|1|
- |1|10|1|1|10|16|4|
-
- ### packing style convention
-
- In practice, elempack 1, 4, 8 are the most common cases. It is possible to use any other packing style in theory.
-
- The following table show the packing axis used in ncnn for different dimension.
-
- |dims|packing axis|shape before packing|shape after packing|
- |---|---|---|---|
- |1|w|w|w/elempack|
- |2|h|w, h|w, h/elempack|
- |3|c|w, h, c|w, h, c/elempack|
-
- If the packing axis dim is not evenly divisible by elempack, zero padding may be used.
-
- ```
- outw = (w + elempack - 1) / elempack;
- ```
-
- The following snippet shows the memory layout after elempack=4 on 3-dim Mat
-
- ```
- // w=2 h=3 c=4 elempack=1
- 0 1
- 2 3
- 4 5
-
- 6 7
- 8 9
- 10 11
-
- 12 13
- 14 15
- 16 17
-
- 18 19
- 20 21
- 22 23
-
- // w=2 h=3 c=1 elempack=4
- (0,6,12,18) (1,7,13,19)
- (2,8,14,20) (3,9,15,21)
- (4,10,16,22) (5,11,17,23)
- ```
-
- ### how to convert elempack
-
- There is a convenient wrapper function provided
- ```
- // convert to elempack 4 if packing axis dim is evenly divisible by elempack
- // return the identity Mat otherwise
- ncnn::Mat a;
- ncnn::Mat a_packed;
- ncnn::convert_packing(a, a_packed, 4);
- if (a_packed.elempack == 4)
- {
- // check if packing is successful
- }
-
- // convert to packing 1, aka unpacking, shall be always successful
- ncnn::Mat b;
- ncnn::Mat b_unpacked;
- ncnn::convert_packing(b, b_unpacked, 1);
- ```
-
- ### handle general interleaved data
-
- Here is an example of using convert packing to convert RGB interleaved data to planar
-
- **NOTE:** The following code is just presented to explain what packing is and the conversion process. Do not use it in production due to its poor performance. Do use ncnn::Mat::from_pixels()
-
- ```cpp
- // rgb_interleaved_u8 is RGB RGB RGB ...
- // rgb_interleaved_u8.w = w;
- // rgb_interleaved_u8.h = h;
- // rgb_interleaved_u8.c = 1;
- // rgb_interleaved_u8.elemsize = 3;
- // rgb_interleaved_u8.elempack = 3;
-
- ncnn::Mat rgb_interleaved_u8(w, h, 1, 3, 3);
- ncnn::Mat rgb_planar_u8;
-
- ncnn::convert_packing(rgb_interleaved_u8, rgb_planar_u8, 1);
-
- // rgb_planar_u8 is now RRR ... GGG ... BBB ...
- // rgb_planar_u8.w = w;
- // rgb_planar_u8.h = h;
- // rgb_planar_u8.c = 3;
- // rgb_planar_u8.elemsize = 1;
- // rgb_planar_u8.elempack = 1;
- ```
|