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