1 // Copyright 2016 The Draco Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 #include "draco/compression/attributes/sequential_integer_attribute_encoder.h"
16
17 #include "draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h"
18 #include "draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_encoding_transform.h"
19 #include "draco/compression/entropy/symbol_encoding.h"
20 #include "draco/core/bit_utils.h"
21
22 namespace draco {
23
SequentialIntegerAttributeEncoder()24 SequentialIntegerAttributeEncoder::SequentialIntegerAttributeEncoder() {}
25
Init(PointCloudEncoder * encoder,int attribute_id)26 bool SequentialIntegerAttributeEncoder::Init(PointCloudEncoder *encoder,
27 int attribute_id) {
28 if (!SequentialAttributeEncoder::Init(encoder, attribute_id)) {
29 return false;
30 }
31 if (GetUniqueId() == SEQUENTIAL_ATTRIBUTE_ENCODER_INTEGER) {
32 // When encoding integers, this encoder currently works only for integer
33 // attributes up to 32 bits.
34 switch (attribute()->data_type()) {
35 case DT_INT8:
36 case DT_UINT8:
37 case DT_INT16:
38 case DT_UINT16:
39 case DT_INT32:
40 case DT_UINT32:
41 break;
42 default:
43 return false;
44 }
45 }
46 // Init prediction scheme.
47 const PredictionSchemeMethod prediction_scheme_method =
48 GetPredictionMethodFromOptions(attribute_id, *encoder->options());
49
50 prediction_scheme_ = CreateIntPredictionScheme(prediction_scheme_method);
51
52 if (prediction_scheme_ && !InitPredictionScheme(prediction_scheme_.get())) {
53 prediction_scheme_ = nullptr;
54 }
55
56 return true;
57 }
58
TransformAttributeToPortableFormat(const std::vector<PointIndex> & point_ids)59 bool SequentialIntegerAttributeEncoder::TransformAttributeToPortableFormat(
60 const std::vector<PointIndex> &point_ids) {
61 if (encoder()) {
62 if (!PrepareValues(point_ids, encoder()->point_cloud()->num_points())) {
63 return false;
64 }
65 } else {
66 if (!PrepareValues(point_ids, 0)) {
67 return false;
68 }
69 }
70
71 // Update point to attribute mapping with the portable attribute if the
72 // attribute is a parent attribute (for now, we can skip it otherwise).
73 if (is_parent_encoder()) {
74 // First create map between original attribute value indices and new ones
75 // (determined by the encoding order).
76 const PointAttribute *const orig_att = attribute();
77 PointAttribute *const portable_att = portable_attribute();
78 IndexTypeVector<AttributeValueIndex, AttributeValueIndex>
79 value_to_value_map(orig_att->size());
80 for (int i = 0; i < point_ids.size(); ++i) {
81 value_to_value_map[orig_att->mapped_index(point_ids[i])] =
82 AttributeValueIndex(i);
83 }
84 if (portable_att->is_mapping_identity()) {
85 portable_att->SetExplicitMapping(encoder()->point_cloud()->num_points());
86 }
87 // Go over all points of the original attribute and update the mapping in
88 // the portable attribute.
89 for (PointIndex i(0); i < encoder()->point_cloud()->num_points(); ++i) {
90 portable_att->SetPointMapEntry(
91 i, value_to_value_map[orig_att->mapped_index(i)]);
92 }
93 }
94 return true;
95 }
96
97 std::unique_ptr<PredictionSchemeTypedEncoderInterface<int32_t>>
CreateIntPredictionScheme(PredictionSchemeMethod method)98 SequentialIntegerAttributeEncoder::CreateIntPredictionScheme(
99 PredictionSchemeMethod method) {
100 return CreatePredictionSchemeForEncoder<
101 int32_t, PredictionSchemeWrapEncodingTransform<int32_t>>(
102 method, attribute_id(), encoder());
103 }
104
EncodeValues(const std::vector<PointIndex> & point_ids,EncoderBuffer * out_buffer)105 bool SequentialIntegerAttributeEncoder::EncodeValues(
106 const std::vector<PointIndex> &point_ids, EncoderBuffer *out_buffer) {
107 // Initialize general quantization data.
108 const PointAttribute *const attrib = attribute();
109 if (attrib->size() == 0) {
110 return true;
111 }
112
113 int8_t prediction_scheme_method = PREDICTION_NONE;
114 if (prediction_scheme_) {
115 if (!SetPredictionSchemeParentAttributes(prediction_scheme_.get())) {
116 return false;
117 }
118 prediction_scheme_method =
119 static_cast<int8_t>(prediction_scheme_->GetPredictionMethod());
120 }
121 out_buffer->Encode(prediction_scheme_method);
122 if (prediction_scheme_) {
123 out_buffer->Encode(
124 static_cast<int8_t>(prediction_scheme_->GetTransformType()));
125 }
126
127 const int num_components = portable_attribute()->num_components();
128 const int num_values =
129 static_cast<int>(num_components * portable_attribute()->size());
130 const int32_t *const portable_attribute_data = GetPortableAttributeData();
131
132 // We need to keep the portable data intact, but several encoding steps can
133 // result in changes of this data, e.g., by applying prediction schemes that
134 // change the data in place. To preserve the portable data we store and
135 // process all encoded data in a separate array.
136 std::vector<int32_t> encoded_data(num_values);
137
138 // All integer values are initialized. Process them using the prediction
139 // scheme if we have one.
140 if (prediction_scheme_) {
141 prediction_scheme_->ComputeCorrectionValues(
142 portable_attribute_data, &encoded_data[0], num_values, num_components,
143 point_ids.data());
144 }
145
146 if (prediction_scheme_ == nullptr ||
147 !prediction_scheme_->AreCorrectionsPositive()) {
148 const int32_t *const input =
149 prediction_scheme_ ? encoded_data.data() : portable_attribute_data;
150 ConvertSignedIntsToSymbols(input, num_values,
151 reinterpret_cast<uint32_t *>(&encoded_data[0]));
152 }
153
154 if (encoder() == nullptr || encoder()->options()->GetGlobalBool(
155 "use_built_in_attribute_compression", true)) {
156 out_buffer->Encode(static_cast<uint8_t>(1));
157 Options symbol_encoding_options;
158 if (encoder() != nullptr) {
159 SetSymbolEncodingCompressionLevel(&symbol_encoding_options,
160 10 - encoder()->options()->GetSpeed());
161 }
162 if (!EncodeSymbols(reinterpret_cast<uint32_t *>(encoded_data.data()),
163 static_cast<int>(point_ids.size()) * num_components,
164 num_components, &symbol_encoding_options, out_buffer)) {
165 return false;
166 }
167 } else {
168 // No compression. Just store the raw integer values, using the number of
169 // bytes as needed.
170
171 // To compute the maximum bit-length, first OR all values.
172 uint32_t masked_value = 0;
173 for (uint32_t i = 0; i < static_cast<uint32_t>(num_values); ++i) {
174 masked_value |= encoded_data[i];
175 }
176 // Compute the msb of the ORed value.
177 int value_msb_pos = 0;
178 if (masked_value != 0) {
179 value_msb_pos = MostSignificantBit(masked_value);
180 }
181 const int num_bytes = 1 + value_msb_pos / 8;
182
183 out_buffer->Encode(static_cast<uint8_t>(0));
184 out_buffer->Encode(static_cast<uint8_t>(num_bytes));
185
186 if (num_bytes == DataTypeLength(DT_INT32)) {
187 out_buffer->Encode(encoded_data.data(), sizeof(int32_t) * num_values);
188 } else {
189 for (uint32_t i = 0; i < static_cast<uint32_t>(num_values); ++i) {
190 out_buffer->Encode(encoded_data.data() + i, num_bytes);
191 }
192 }
193 }
194 if (prediction_scheme_) {
195 prediction_scheme_->EncodePredictionData(out_buffer);
196 }
197 return true;
198 }
199
PrepareValues(const std::vector<PointIndex> & point_ids,int num_points)200 bool SequentialIntegerAttributeEncoder::PrepareValues(
201 const std::vector<PointIndex> &point_ids, int num_points) {
202 // Convert all values to int32_t format.
203 const PointAttribute *const attrib = attribute();
204 const int num_components = attrib->num_components();
205 const int num_entries = static_cast<int>(point_ids.size());
206 PreparePortableAttribute(num_entries, num_components, num_points);
207 int32_t dst_index = 0;
208 int32_t *const portable_attribute_data = GetPortableAttributeData();
209 for (PointIndex pi : point_ids) {
210 const AttributeValueIndex att_id = attrib->mapped_index(pi);
211 if (!attrib->ConvertValue<int32_t>(att_id,
212 portable_attribute_data + dst_index)) {
213 return false;
214 }
215 dst_index += num_components;
216 }
217 return true;
218 }
219
PreparePortableAttribute(int num_entries,int num_components,int num_points)220 void SequentialIntegerAttributeEncoder::PreparePortableAttribute(
221 int num_entries, int num_components, int num_points) {
222 GeometryAttribute va;
223 va.Init(attribute()->attribute_type(), nullptr, num_components, DT_INT32,
224 false, num_components * DataTypeLength(DT_INT32), 0);
225 std::unique_ptr<PointAttribute> port_att(new PointAttribute(va));
226 port_att->Reset(num_entries);
227 SetPortableAttribute(std::move(port_att));
228 if (num_points) {
229 portable_attribute()->SetExplicitMapping(num_points);
230 }
231 }
232
233 } // namespace draco
234