1 #include <mbgl/programs/binary_program.hpp>
2 
3 #include <protozero/pbf_reader.hpp>
4 #include <protozero/pbf_writer.hpp>
5 #include <utility>
6 #include <stdexcept>
7 
8 template <class Binding>
parseBinding(protozero::pbf_reader && pbf)9 static std::pair<const std::string, Binding> parseBinding(protozero::pbf_reader&& pbf) {
10     bool hasName = false, hasValue = false;
11     std::pair<std::string, Binding> binding;
12     while (pbf.next()) {
13         switch (pbf.tag()) {
14         case 1: // name
15             binding.first = pbf.get_string();
16             hasName = true;
17             break;
18         case 2: // value
19             binding.second = pbf.get_uint32();
20             hasValue = true;
21             break;
22         default:
23             pbf.skip();
24             break;
25         }
26     }
27     if (!hasName || !hasValue) {
28         throw std::runtime_error("BinaryProgram binding is missing required fields");
29     }
30     return binding;
31 }
32 
33 namespace mbgl {
34 
BinaryProgram(std::string && data)35 BinaryProgram::BinaryProgram(std::string&& data) {
36     bool hasFormat = false, hasCode = false;
37     protozero::pbf_reader pbf(data);
38     while (pbf.next()) {
39         switch (pbf.tag()) {
40         case 1: // format
41             binaryFormat = pbf.get_uint32();
42             hasFormat = true;
43             break;
44         case 2: // code
45             binaryCode = pbf.get_bytes();
46             hasCode = true;
47             break;
48         case 3: // variable
49             attributes.emplace_back(parseBinding<gl::AttributeLocation>(pbf.get_message()));
50             break;
51         case 4: // uniform
52             uniforms.emplace_back(parseBinding<gl::UniformLocation>(pbf.get_message()));
53             break;
54         case 5: // identifier
55         default:
56             binaryIdentifier = pbf.get_string();
57             break;
58         }
59     }
60 
61     if (!hasFormat || !hasCode) {
62         throw std::runtime_error("BinaryProgram is missing required fields");
63     }
64 }
65 
BinaryProgram(gl::BinaryProgramFormat binaryFormat_,std::string && binaryCode_,std::string binaryIdentifier_,std::vector<std::pair<const std::string,gl::AttributeLocation>> && attributes_,std::vector<std::pair<const std::string,gl::UniformLocation>> && uniforms_)66 BinaryProgram::BinaryProgram(
67     gl::BinaryProgramFormat binaryFormat_,
68     std::string&& binaryCode_,
69     std::string binaryIdentifier_,
70     std::vector<std::pair<const std::string, gl::AttributeLocation>>&& attributes_,
71     std::vector<std::pair<const std::string, gl::UniformLocation>>&& uniforms_)
72     : binaryFormat(binaryFormat_),
73       binaryCode(std::move(binaryCode_)),
74       binaryIdentifier(std::move(binaryIdentifier_)),
75       attributes(std::move(attributes_)),
76       uniforms(std::move(uniforms_)) {
77 }
78 
serialize() const79 std::string BinaryProgram::serialize() const {
80     std::string data;
81     data.reserve(32 + binaryCode.size() + uniforms.size() * 32 + attributes.size() * 32);
82     protozero::pbf_writer pbf(data);
83     pbf.add_uint32(1 /* format */, binaryFormat);
84     pbf.add_bytes(2 /* code */, binaryCode.data(), binaryCode.size());
85     for (const auto& binding : attributes) {
86         protozero::pbf_writer pbf_binding(pbf, 3 /* attribute */);
87         pbf_binding.add_string(1 /* name */, binding.first);
88         pbf_binding.add_uint32(2 /* value */, binding.second);
89     }
90     for (const auto& binding : uniforms) {
91         protozero::pbf_writer pbf_binding(pbf, 4 /* uniform */);
92         pbf_binding.add_string(1 /* name */, binding.first);
93         pbf_binding.add_uint32(2 /* value */, binding.second);
94     }
95     if (!binaryIdentifier.empty()) {
96         pbf.add_string(5 /* identifier */, binaryIdentifier);
97     }
98     return data;
99 }
100 
attributeLocation(const std::string & name) const101 optional<gl::AttributeLocation> BinaryProgram::attributeLocation(const std::string& name) const {
102     for (const auto& pair : attributes) {
103         if (pair.first == name) {
104             return pair.second;
105         }
106     }
107     return {};
108 }
109 
uniformLocation(const std::string & name) const110 gl::UniformLocation BinaryProgram::uniformLocation(const std::string& name) const {
111     for (const auto& pair : uniforms) {
112         if (pair.first == name) {
113             return pair.second;
114         }
115     }
116     return -1;
117 }
118 
119 } // namespace mbgl
120