Flutter Engine
The Flutter Engine
buffer_bindings_gles.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <cstring>
8#include <vector>
9
16
17namespace impeller {
18
19// This prefix is used in the names of inputs generated by ANGLE's framebuffer
20// fetch emulation.
21static constexpr std::string_view kAngleInputAttachmentPrefix =
22 "ANGLEInputAttachment";
23
25
27
29 const ProcTableGLES& gl,
30 const std::vector<ShaderStageIOSlot>& p_inputs,
31 const std::vector<ShaderStageBufferLayout>& layouts) {
32 std::vector<VertexAttribPointer> vertex_attrib_arrays;
33 for (auto i = 0u; i < p_inputs.size(); i++) {
34 const auto& input = p_inputs[i];
35 const auto& layout = layouts[input.binding];
36 VertexAttribPointer attrib;
37 attrib.index = input.location;
38 // Component counts must be 1, 2, 3 or 4. Do that validation now.
39 if (input.vec_size < 1u || input.vec_size > 4u) {
40 return false;
41 }
42 attrib.size = input.vec_size;
43 auto type = ToVertexAttribType(input.type);
44 if (!type.has_value()) {
45 return false;
46 }
47 attrib.type = type.value();
48 attrib.normalized = GL_FALSE;
49 attrib.offset = input.offset;
50 attrib.stride = layout.stride;
51 vertex_attrib_arrays.emplace_back(attrib);
52 }
53 vertex_attrib_arrays_ = std::move(vertex_attrib_arrays);
54 return true;
55}
56
57static std::string NormalizeUniformKey(const std::string& key) {
58 std::string result;
59 result.reserve(key.length());
60 for (char ch : key) {
61 if (ch != '_') {
62 result.push_back(toupper(ch));
63 }
64 }
65 return result;
66}
67
68static std::string CreateUniformMemberKey(const std::string& struct_name,
69 const std::string& member,
70 bool is_array) {
71 std::string result;
72 result.reserve(struct_name.length() + member.length() + (is_array ? 4 : 1));
73 result += struct_name;
74 if (!member.empty()) {
75 result += '.';
76 result += member;
77 }
78 if (is_array) {
79 result += "[0]";
80 }
82}
83
84static std::string CreateUniformMemberKey(
85 const std::string& non_struct_member) {
86 return NormalizeUniformKey(non_struct_member);
87}
88
90 GLuint program) {
91 if (!gl.IsProgram(program)) {
92 return false;
93 }
94 GLint max_name_size = 0;
95 gl.GetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_name_size);
96
97 GLint uniform_count = 0;
98 gl.GetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniform_count);
99
100 // Query the Program for all active uniform locations, and
101 // record this via normalized key.
102 for (GLint i = 0; i < uniform_count; i++) {
103 std::vector<GLchar> name;
104 name.resize(max_name_size);
105 GLsizei written_count = 0u;
106 GLint uniform_var_size = 0u;
107 GLenum uniform_type = GL_FLOAT;
108 // Note: Active uniforms are defined as uniforms that may have an impact on
109 // the output of the shader. Drivers are allowed to (and often do)
110 // optimize out unused uniforms.
111 gl.GetActiveUniform(program, // program
112 i, // index
113 max_name_size, // buffer_size
114 &written_count, // length
115 &uniform_var_size, // size
116 &uniform_type, // type
117 name.data() // name
118 );
119
120 // Skip unrecognized variables generated by ANGLE.
121 if (gl.GetCapabilities()->IsANGLE()) {
122 if (written_count >=
123 static_cast<GLsizei>(kAngleInputAttachmentPrefix.length()) &&
124 std::string_view(name.data(), kAngleInputAttachmentPrefix.length()) ==
126 continue;
127 }
128 }
129
130 auto location = gl.GetUniformLocation(program, name.data());
131 if (location == -1) {
132 VALIDATION_LOG << "Could not query the location of an active uniform.";
133 return false;
134 }
135 if (written_count <= 0) {
136 VALIDATION_LOG << "Uniform name could not be read for active uniform.";
137 return false;
138 }
139 uniform_locations_[NormalizeUniformKey(std::string{
140 name.data(), static_cast<size_t>(written_count)})] = location;
141 }
142 return true;
143}
144
146 size_t vertex_offset) const {
147 for (const auto& array : vertex_attrib_arrays_) {
148 gl.EnableVertexAttribArray(array.index);
149 gl.VertexAttribPointer(array.index, // index
150 array.size, // size (must be 1, 2, 3, or 4)
151 array.type, // type
152 array.normalized, // normalized
153 array.stride, // stride
154 reinterpret_cast<const GLvoid*>(static_cast<GLsizei>(
155 vertex_offset + array.offset)) // pointer
156 );
157 }
158
159 return true;
160}
161
163 Allocator& transients_allocator,
164 const Bindings& vertex_bindings,
165 const Bindings& fragment_bindings) {
166 for (const auto& buffer : vertex_bindings.buffers) {
167 if (!BindUniformBuffer(gl, transients_allocator, buffer.view)) {
168 return false;
169 }
170 }
171 for (const auto& buffer : fragment_bindings.buffers) {
172 if (!BindUniformBuffer(gl, transients_allocator, buffer.view)) {
173 return false;
174 }
175 }
176
177 std::optional<size_t> next_unit_index =
178 BindTextures(gl, vertex_bindings, ShaderStage::kVertex);
179 if (!next_unit_index.has_value()) {
180 return false;
181 }
182
183 if (!BindTextures(gl, fragment_bindings, ShaderStage::kFragment,
184 *next_unit_index)
185 .has_value()) {
186 return false;
187 }
188
189 return true;
190}
191
193 for (const auto& array : vertex_attrib_arrays_) {
194 gl.DisableVertexAttribArray(array.index);
195 }
196 return true;
197}
198
199GLint BufferBindingsGLES::ComputeTextureLocation(
200 const ShaderMetadata* metadata) {
201 auto location = binding_map_.find(metadata->name);
202 if (location != binding_map_.end()) {
203 return location->second[0];
204 }
205 auto& locations = binding_map_[metadata->name] = {};
206 auto computed_location =
207 uniform_locations_.find(CreateUniformMemberKey(metadata->name));
208 if (computed_location == uniform_locations_.end()) {
209 locations.push_back(-1);
210 } else {
211 locations.push_back(computed_location->second);
212 }
213 return locations[0];
214}
215
216const std::vector<GLint>& BufferBindingsGLES::ComputeUniformLocations(
217 const ShaderMetadata* metadata) {
218 auto location = binding_map_.find(metadata->name);
219 if (location != binding_map_.end()) {
220 return location->second;
221 }
222
223 // For each metadata member, look up the binding location and record
224 // it in the binding map.
225 auto& locations = binding_map_[metadata->name] = {};
226 for (const auto& member : metadata->members) {
227 if (member.type == ShaderType::kVoid) {
228 // Void types are used for padding. We are obviously not going to find
229 // mappings for these. Keep going.
230 locations.push_back(-1);
231 continue;
232 }
233
234 size_t element_count = member.array_elements.value_or(1);
235 const auto member_key =
236 CreateUniformMemberKey(metadata->name, member.name, element_count > 1);
237 const auto computed_location = uniform_locations_.find(member_key);
238 if (computed_location == uniform_locations_.end()) {
239 // Uniform was not active.
240 locations.push_back(-1);
241 continue;
242 }
243 locations.push_back(computed_location->second);
244 }
245 return locations;
246}
247
248bool BufferBindingsGLES::BindUniformBuffer(const ProcTableGLES& gl,
249 Allocator& transients_allocator,
250 const BufferResource& buffer) {
251 const auto* metadata = buffer.GetMetadata();
252 auto device_buffer = buffer.resource.buffer;
253 if (!device_buffer) {
254 VALIDATION_LOG << "Device buffer not found.";
255 return false;
256 }
257 const auto& device_buffer_gles = DeviceBufferGLES::Cast(*device_buffer);
258 const uint8_t* buffer_ptr =
259 device_buffer_gles.GetBufferData() + buffer.resource.range.offset;
260
261 if (metadata->members.empty()) {
262 VALIDATION_LOG << "Uniform buffer had no members. This is currently "
263 "unsupported in the OpenGL ES backend. Use a uniform "
264 "buffer block.";
265 return false;
266 }
267
268 const auto& locations = ComputeUniformLocations(metadata);
269 for (auto i = 0u; i < metadata->members.size(); i++) {
270 const auto& member = metadata->members[i];
271 auto location = locations[i];
272 // Void type or inactive uniform.
273 if (location == -1 || member.type == ShaderType::kVoid) {
274 continue;
275 }
276
277 size_t element_count = member.array_elements.value_or(1);
278 size_t element_stride = member.byte_length / element_count;
279 auto* buffer_data =
280 reinterpret_cast<const GLfloat*>(buffer_ptr + member.offset);
281
282 std::vector<uint8_t> array_element_buffer;
283 if (element_count > 1) {
284 // When binding uniform arrays, the elements must be contiguous. Copy
285 // the uniforms to a temp buffer to eliminate any padding needed by the
286 // other backends.
287 array_element_buffer.resize(member.size * element_count);
288 for (size_t element_i = 0; element_i < element_count; element_i++) {
289 std::memcpy(array_element_buffer.data() + element_i * member.size,
290 reinterpret_cast<const char*>(buffer_data) +
291 element_i * element_stride,
292 member.size);
293 }
294 buffer_data =
295 reinterpret_cast<const GLfloat*>(array_element_buffer.data());
296 }
297
298 switch (member.type) {
300 switch (member.size) {
301 case sizeof(Matrix):
302 gl.UniformMatrix4fv(location, // location
303 element_count, // count
304 GL_FALSE, // normalize
305 buffer_data // data
306 );
307 continue;
308 case sizeof(Vector4):
309 gl.Uniform4fv(location, // location
310 element_count, // count
311 buffer_data // data
312 );
313 continue;
314 case sizeof(Vector3):
315 gl.Uniform3fv(location, // location
316 element_count, // count
317 buffer_data // data
318 );
319 continue;
320 case sizeof(Vector2):
321 gl.Uniform2fv(location, // location
322 element_count, // count
323 buffer_data // data
324 );
325 continue;
326 case sizeof(Scalar):
327 gl.Uniform1fv(location, // location
328 element_count, // count
329 buffer_data // data
330 );
331 continue;
332 }
333 VALIDATION_LOG << "Size " << member.size
334 << " could not be mapped ShaderType::kFloat for key: "
335 << member.name;
354 VALIDATION_LOG << "Could not bind uniform buffer data for key: "
355 << member.name << " : " << static_cast<int>(member.type);
356 return false;
357 }
358 }
359 return true;
360}
361
362std::optional<size_t> BufferBindingsGLES::BindTextures(
363 const ProcTableGLES& gl,
364 const Bindings& bindings,
365 ShaderStage stage,
366 size_t unit_start_index) {
367 size_t active_index = unit_start_index;
368 for (const auto& data : bindings.sampled_images) {
369 const auto& texture_gles = TextureGLES::Cast(*data.texture.resource);
370 if (data.texture.GetMetadata() == nullptr) {
371 VALIDATION_LOG << "No metadata found for texture binding.";
372 return std::nullopt;
373 }
374
375 auto location = ComputeTextureLocation(data.texture.GetMetadata());
376 if (location == -1) {
377 return std::nullopt;
378 }
379
380 //--------------------------------------------------------------------------
381 /// Set the active texture unit.
382 ///
383 if (active_index >= gl.GetCapabilities()->GetMaxTextureUnits(stage)) {
384 VALIDATION_LOG << "Texture units specified exceed the capabilities for "
385 "this shader stage.";
386 return std::nullopt;
387 }
388 gl.ActiveTexture(GL_TEXTURE0 + active_index);
389
390 //--------------------------------------------------------------------------
391 /// Bind the texture.
392 ///
393 if (!texture_gles.Bind()) {
394 return std::nullopt;
395 }
396
397 //--------------------------------------------------------------------------
398 /// If there is a sampler for the texture at the same index, configure the
399 /// bound texture using that sampler.
400 ///
401 const auto& sampler_gles = SamplerGLES::Cast(*data.sampler);
402 if (!sampler_gles.ConfigureBoundTexture(texture_gles, gl)) {
403 return std::nullopt;
404 }
405
406 //--------------------------------------------------------------------------
407 /// Set the texture uniform location.
408 ///
409 gl.Uniform1i(location, active_index);
410
411 //--------------------------------------------------------------------------
412 /// Bump up the active index at binding.
413 ///
414 active_index++;
415 }
416 return active_index;
417}
418
419} // namespace impeller
GLenum type
An object that allocates device memory.
Definition: allocator.h:22
static DeviceBufferGLES & Cast(DeviceBuffer &base)
Definition: backend_cast.h:13
bool ReadUniformsBindings(const ProcTableGLES &gl, GLuint program)
bool BindVertexAttributes(const ProcTableGLES &gl, size_t vertex_offset) const
bool RegisterVertexStageInput(const ProcTableGLES &gl, const std::vector< ShaderStageIOSlot > &inputs, const std::vector< ShaderStageBufferLayout > &layouts)
bool BindUniformData(const ProcTableGLES &gl, Allocator &transients_allocator, const Bindings &vertex_bindings, const Bindings &fragment_bindings)
bool UnbindVertexAttributes(const ProcTableGLES &gl) const
GAsyncResult * result
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
Point Vector2
Definition: point.h:326
float Scalar
Definition: scalar.h:18
static std::string CreateUniformMemberKey(const std::string &struct_name, const std::string &member, bool is_array)
static constexpr std::string_view kAngleInputAttachmentPrefix
Resource< BufferView > BufferResource
Definition: command.h:57
static std::string NormalizeUniformKey(const std::string &key)
constexpr std::optional< GLenum > ToVertexAttribType(ShaderType type)
Definition: formats_gles.h:138
gl
Definition: malisc.py:41
SK_API sk_sp< PrecompileColorFilter > Matrix()
std::vector< BufferAndUniformSlot > buffers
Definition: command.h:75
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
#define VALIDATION_LOG
Definition: validation.h:73