Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
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
19
20namespace impeller {
21
22// This prefix is used in the names of inputs generated by ANGLE's framebuffer
23// fetch emulation.
24static constexpr std::string_view kAngleInputAttachmentPrefix =
25 "ANGLEInputAttachment";
26
28
30
32 const ProcTableGLES& gl,
33 const std::vector<ShaderStageIOSlot>& p_inputs,
34 const std::vector<ShaderStageBufferLayout>& layouts) {
35 std::vector<std::vector<VertexAttribPointer>> vertex_attrib_arrays(
36 layouts.size());
37 // Every layout corresponds to a vertex binding.
38 // As we record, separate the attributes into buckets for each layout in
39 // ascending order. We do this because later on, we'll need to associate each
40 // of the attributes with bound buffers corresponding to the binding.
41 for (auto layout_i = 0u; layout_i < layouts.size(); layout_i++) {
42 const auto& layout = layouts[layout_i];
43 for (const auto& input : p_inputs) {
44 if (input.binding != layout_i) {
45 continue;
46 }
47 VertexAttribPointer attrib;
48 attrib.index = input.location;
49 // Component counts must be 1, 2, 3 or 4. Do that validation now.
50 if (input.vec_size < 1u || input.vec_size > 4u) {
51 return false;
52 }
53 attrib.size = input.vec_size;
54 auto type = ToVertexAttribType(input.type);
55 if (!type.has_value()) {
56 return false;
57 }
58 attrib.type = type.value();
59 attrib.normalized = GL_FALSE;
60 attrib.offset = input.offset;
61 attrib.stride = layout.stride;
62 vertex_attrib_arrays[layout_i].push_back(attrib);
63 }
64 }
65 vertex_attrib_arrays_ = std::move(vertex_attrib_arrays);
66 return true;
67}
68
69static std::string NormalizeUniformKey(const std::string& key) {
70 std::string result;
71 result.reserve(key.length());
72 for (char ch : key) {
73 if (ch != '_') {
74 result.push_back(toupper(ch));
75 }
76 }
77 return result;
78}
79
80static std::string CreateUniformMemberKey(const std::string& struct_name,
81 const std::string& member,
82 bool is_array) {
83 std::string result;
84 result.reserve(struct_name.length() + member.length() + (is_array ? 4 : 1));
85 result += struct_name;
86 if (!member.empty()) {
87 result += '.';
88 result += member;
89 }
90 if (is_array) {
91 result += "[0]";
92 }
93 return NormalizeUniformKey(result);
94}
95
96static std::string CreateUniformMemberKey(
97 const std::string& non_struct_member) {
98 return NormalizeUniformKey(non_struct_member);
99}
100
102 GLuint program) {
103 if (!gl.IsProgram(program)) {
104 return false;
105 }
106 program_handle_ = program;
107 if (gl.GetDescription()->GetGlVersion().IsAtLeast(Version{3, 0, 0})) {
108 return ReadUniformsBindingsV3(gl, program);
109 }
110 return ReadUniformsBindingsV2(gl, program);
111}
112
113bool BufferBindingsGLES::ReadUniformsBindingsV3(const ProcTableGLES& gl,
114 GLuint program) {
115 program_handle_ = program;
116 GLint uniform_blocks = 0;
117 gl.GetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &uniform_blocks);
118 for (GLint i = 0; i < uniform_blocks; i++) {
119 GLint name_length = 0;
120 gl.GetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_NAME_LENGTH,
121 &name_length);
122
123 std::vector<GLchar> name;
124 name.resize(name_length);
125 GLint length = 0;
126 gl.GetActiveUniformBlockName(program, i, name_length, &length, name.data());
127
128 GLuint block_index = gl.GetUniformBlockIndex(program, name.data());
129 gl.UniformBlockBinding(program_handle_, block_index, i);
130
131 ubo_locations_[std::string{name.data(), static_cast<size_t>(length)}] =
132 std::make_pair(block_index, i);
133 }
134 use_ubo_ = true;
135 return ReadUniformsBindingsV2(gl, program);
136}
137
138bool BufferBindingsGLES::ReadUniformsBindingsV2(const ProcTableGLES& gl,
139 GLuint program) {
140 GLint max_name_size = 0;
141 gl.GetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_name_size);
142
143 GLint uniform_count = 0;
144 gl.GetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniform_count);
145
146 // Query the Program for all active uniform locations, and
147 // record this via normalized key.
148 for (GLint i = 0; i < uniform_count; i++) {
149 std::vector<GLchar> name;
150 name.resize(max_name_size);
151 GLsizei written_count = 0u;
152 GLint uniform_var_size = 0u;
153 GLenum uniform_type = GL_FLOAT;
154 // Note: Active uniforms are defined as uniforms that may have an impact on
155 // the output of the shader. Drivers are allowed to (and often do)
156 // optimize out unused uniforms.
157 gl.GetActiveUniform(program, // program
158 i, // index
159 max_name_size, // buffer_size
160 &written_count, // length
161 &uniform_var_size, // size
162 &uniform_type, // type
163 name.data() // name
164 );
165
166 // Skip unrecognized variables generated by ANGLE.
167 if (gl.GetCapabilities()->IsANGLE()) {
168 if (written_count >=
169 static_cast<GLsizei>(kAngleInputAttachmentPrefix.length()) &&
170 std::string_view(name.data(), kAngleInputAttachmentPrefix.length()) ==
172 continue;
173 }
174 }
175
176 auto location = gl.GetUniformLocation(program, name.data());
177 if (location == -1) {
178 if (use_ubo_) {
179 continue;
180 }
181 VALIDATION_LOG << "Could not query the location of an active uniform.";
182 return false;
183 }
184 if (written_count <= 0) {
185 VALIDATION_LOG << "Uniform name could not be read for active uniform.";
186 return false;
187 }
188 uniform_locations_[NormalizeUniformKey(std::string{
189 name.data(), static_cast<size_t>(written_count)})] = location;
190 }
191 return true;
192}
193
195 size_t binding,
196 size_t vertex_offset) {
197 if (binding >= vertex_attrib_arrays_.size()) {
198 return false;
199 }
200
201 if (!gl.GetCapabilities()->IsES()) {
202 FML_DCHECK(vertex_array_object_ == 0);
203 gl.GenVertexArrays(1, &vertex_array_object_);
204 gl.BindVertexArray(vertex_array_object_);
205 }
206
207 for (const auto& array : vertex_attrib_arrays_[binding]) {
208 gl.EnableVertexAttribArray(array.index);
209 gl.VertexAttribPointer(array.index, // index
210 array.size, // size (must be 1, 2, 3, or 4)
211 array.type, // type
212 array.normalized, // normalized
213 array.stride, // stride
214 reinterpret_cast<const GLvoid*>(static_cast<GLsizei>(
215 vertex_offset + array.offset)) // pointer
216 );
217 }
218
219 return true;
220}
221
223 const ProcTableGLES& gl,
224 const std::vector<TextureAndSampler>& bound_textures,
225 const std::vector<BufferResource>& bound_buffers,
226 Range texture_range,
227 Range buffer_range) {
228 for (auto i = 0u; i < buffer_range.length; i++) {
229 if (!BindUniformBuffer(gl, bound_buffers[buffer_range.offset + i])) {
230 return false;
231 }
232 }
233 std::optional<size_t> next_unit_index =
234 BindTextures(gl, bound_textures, texture_range, ShaderStage::kVertex);
235 if (!next_unit_index.has_value()) {
236 return false;
237 }
238 if (!BindTextures(gl, bound_textures, texture_range, ShaderStage::kFragment,
239 *next_unit_index)
240 .has_value()) {
241 return false;
242 }
243
244 return true;
245}
246
248 for (const auto& array : vertex_attrib_arrays_) {
249 for (const auto& attribute : array) {
250 gl.DisableVertexAttribArray(attribute.index);
251 }
252 }
253 if (!gl.GetCapabilities()->IsES()) {
254 gl.DeleteVertexArrays(1, &vertex_array_object_);
255 vertex_array_object_ = 0;
256 }
257
258 return true;
259}
260
261GLint BufferBindingsGLES::ComputeTextureLocation(
262 const ShaderMetadata* metadata) {
263 auto location = binding_map_.find(metadata->name);
264 if (location != binding_map_.end()) {
265 return location->second[0];
266 }
267 auto& locations = binding_map_[metadata->name] = {};
268 auto computed_location =
269 uniform_locations_.find(CreateUniformMemberKey(metadata->name));
270 if (computed_location == uniform_locations_.end()) {
271 locations.push_back(-1);
272 } else {
273 locations.push_back(computed_location->second);
274 }
275 return locations[0];
276}
277
278const std::vector<GLint>& BufferBindingsGLES::ComputeUniformLocations(
279 const ShaderMetadata* metadata) {
280 BindingMap::iterator location = binding_map_.find(metadata->name);
281 if (location != binding_map_.end()) {
282 return location->second;
283 }
284
285 // For each metadata member, look up the binding location and record
286 // it in the binding map.
287 std::vector<GLint>& locations = binding_map_[metadata->name] = {};
288 locations.reserve(metadata->members.size());
289 for (const ShaderStructMemberMetadata& member : metadata->members) {
290 if (member.type == ShaderType::kVoid) {
291 // Void types are used for padding. We are obviously not going to find
292 // mappings for these. Keep going.
293 locations.push_back(-1);
294 continue;
295 }
296
297 const std::string member_key = CreateUniformMemberKey(
298 metadata->name, member.name, member.array_elements.has_value());
299 const absl::flat_hash_map<std::string, GLint>::iterator computed_location =
300 uniform_locations_.find(member_key);
301 if (computed_location == uniform_locations_.end()) {
302 // Uniform was not active.
303 locations.push_back(-1);
304 continue;
305 }
306 locations.push_back(computed_location->second);
307 }
308 return locations;
309}
310
311bool BufferBindingsGLES::BindUniformBuffer(const ProcTableGLES& gl,
312 const BufferResource& buffer) {
313 const ShaderMetadata* metadata = buffer.GetMetadata();
314 const DeviceBuffer* device_buffer = buffer.resource.GetBuffer();
315 if (!device_buffer) {
316 VALIDATION_LOG << "Device buffer not found.";
317 return false;
318 }
319 const DeviceBufferGLES& device_buffer_gles =
320 DeviceBufferGLES::Cast(*device_buffer);
321
322 if (use_ubo_) {
323 return BindUniformBufferV3(gl, buffer.resource, metadata,
324 device_buffer_gles);
325 }
326 return BindUniformBufferV2(gl, buffer.resource, metadata, device_buffer_gles);
327}
328
329bool BufferBindingsGLES::BindUniformBufferV3(
330 const ProcTableGLES& gl,
331 const BufferView& buffer,
332 const ShaderMetadata* metadata,
333 const DeviceBufferGLES& device_buffer_gles) {
334 absl::flat_hash_map<std::string, std::pair<GLint, GLuint>>::iterator it =
335 ubo_locations_.find(metadata->name);
336 if (it == ubo_locations_.end()) {
337 return BindUniformBufferV2(gl, buffer, metadata, device_buffer_gles);
338 }
339 const auto& [block_index, binding_point] = it->second;
340 if (!device_buffer_gles.BindAndUploadDataIfNecessary(
342 return false;
343 }
344 auto handle = device_buffer_gles.GetHandle();
345 if (!handle.has_value()) {
346 return false;
347 }
348 gl.BindBufferRange(GL_UNIFORM_BUFFER, binding_point, handle.value(),
349 buffer.GetRange().offset, buffer.GetRange().length);
350 return true;
351}
352
353bool BufferBindingsGLES::BindUniformBufferV2(
354 const ProcTableGLES& gl,
355 const BufferView& buffer,
356 const ShaderMetadata* metadata,
357 const DeviceBufferGLES& device_buffer_gles) {
358 const uint8_t* buffer_ptr =
359 device_buffer_gles.GetBufferData() + buffer.GetRange().offset;
360
361 if (metadata->members.empty()) {
362 VALIDATION_LOG << "Uniform buffer had no members. This is currently "
363 "unsupported in the OpenGL ES backend. Use a uniform "
364 "buffer block.";
365 return false;
366 }
367
368 const std::vector<GLint>& locations = ComputeUniformLocations(metadata);
369 for (size_t i = 0u; i < metadata->members.size(); i++) {
370 const ShaderStructMemberMetadata& member = metadata->members[i];
371 GLint location = locations[i];
372 // Void type or inactive uniform.
373 if (location == -1 || member.type == ShaderType::kVoid) {
374 continue;
375 }
376
377 size_t element_count = member.array_elements.value_or(1);
378 size_t element_stride = member.byte_length / element_count;
379 auto* buffer_data =
380 reinterpret_cast<const GLfloat*>(buffer_ptr + member.offset);
381
382 // When binding uniform arrays, the elements must be contiguous. Copy
383 // the uniforms to a temp buffer to eliminate any padding needed by the
384 // other backends if the array elements have padding.
385 std::vector<uint8_t> array_element_buffer;
386 if (element_count > 1 && element_stride != member.size) {
387 array_element_buffer.resize(member.size * element_count);
388 for (size_t element_i = 0; element_i < element_count; element_i++) {
389 std::memcpy(array_element_buffer.data() + element_i * member.size,
390 reinterpret_cast<const char*>(buffer_data) +
391 element_i * element_stride,
392 member.size);
393 }
394 buffer_data =
395 reinterpret_cast<const GLfloat*>(array_element_buffer.data());
396 }
397
398 if (member.type != ShaderType::kFloat) {
399 VALIDATION_LOG << "Unsupported uniform data type for key: " << member.name
400 << ", has type " << static_cast<int>(member.type)
401 << ". Only float uniforms are supported.";
402 return false;
403 }
404
405 switch (member.size) {
406 case sizeof(Matrix):
407 gl.UniformMatrix4fv(location, // location
408 element_count, // count
409 GL_FALSE, // normalize
410 buffer_data // data
411 );
412 continue;
413 case sizeof(Vector4):
414 gl.Uniform4fv(location, // location
415 element_count, // count
416 buffer_data // data
417 );
418 continue;
419 case sizeof(Vector3):
420 gl.Uniform3fv(location, // location
421 element_count, // count
422 buffer_data // data
423 );
424 continue;
425 case sizeof(Vector2):
426 gl.Uniform2fv(location, // location
427 element_count, // count
428 buffer_data // data
429 );
430 continue;
431 case sizeof(Scalar):
432 gl.Uniform1fv(location, // location
433 element_count, // count
434 buffer_data // data
435 );
436 continue;
437 default:
438 VALIDATION_LOG << "Invalid member size binding: " << member.size;
439 return false;
440 }
441 }
442 return true;
443}
444
445std::optional<size_t> BufferBindingsGLES::BindTextures(
446 const ProcTableGLES& gl,
447 const std::vector<TextureAndSampler>& bound_textures,
448 Range texture_range,
449 ShaderStage stage,
450 size_t unit_start_index) {
451 size_t active_index = unit_start_index;
452 for (auto i = 0u; i < texture_range.length; i++) {
453 const TextureAndSampler& data = bound_textures[texture_range.offset + i];
454 if (data.stage != stage) {
455 continue;
456 }
457 const auto& texture_gles = TextureGLES::Cast(*data.texture.resource);
458 if (data.texture.GetMetadata() == nullptr) {
459 VALIDATION_LOG << "No metadata found for texture binding.";
460 return std::nullopt;
461 }
462
463 auto location = ComputeTextureLocation(data.texture.GetMetadata());
464 if (location == -1) {
465 // The texture binding was optimized out of the shader. Continue.
466 continue;
467 }
468
469 //--------------------------------------------------------------------------
470 /// Set the active texture unit.
471 ///
472 if (active_index >= gl.GetCapabilities()->GetMaxTextureUnits(stage)) {
473 VALIDATION_LOG << "Texture units specified exceed the capabilities for "
474 "this shader stage.";
475 return std::nullopt;
476 }
477 gl.ActiveTexture(GL_TEXTURE0 + active_index);
478
479 //--------------------------------------------------------------------------
480 /// Bind the texture.
481 ///
482 if (!texture_gles.Bind()) {
483 return std::nullopt;
484 }
485
486 //--------------------------------------------------------------------------
487 /// If there is a sampler for the texture at the same index, configure the
488 /// bound texture using that sampler.
489 ///
490 const auto& sampler_gles = SamplerGLES::Cast(*data.sampler);
491 if (!sampler_gles.ConfigureBoundTexture(texture_gles, gl)) {
492 return std::nullopt;
493 }
494
495 //--------------------------------------------------------------------------
496 /// Set the texture uniform location.
497 ///
498 gl.Uniform1i(location, active_index);
499
500 //--------------------------------------------------------------------------
501 /// Bump up the active index at binding.
502 ///
503 active_index++;
504 }
505 return active_index;
506}
507
508} // namespace impeller
GLenum type
static DeviceBufferGLES & Cast(DeviceBuffer &base)
bool BindVertexAttributes(const ProcTableGLES &gl, size_t binding, size_t vertex_offset)
bool ReadUniformsBindings(const ProcTableGLES &gl, GLuint program)
bool UnbindVertexAttributes(const ProcTableGLES &gl)
bool RegisterVertexStageInput(const ProcTableGLES &gl, const std::vector< ShaderStageIOSlot > &inputs, const std::vector< ShaderStageBufferLayout > &layouts)
bool BindUniformData(const ProcTableGLES &gl, const std::vector< TextureAndSampler > &bound_textures, const std::vector< BufferResource > &bound_buffers, Range texture_range, Range buffer_range)
const std::shared_ptr< const CapabilitiesGLES > & GetCapabilities() const
const DescriptionGLES * GetDescription() const
static int input(yyscan_t yyscanner)
uint32_t location
#define FML_DCHECK(condition)
Definition logging.h:122
const char * name
Definition fuchsia.cc:49
size_t length
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 disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set profile Make the profiler discard new samples once the profiler sample buffer is full When this flag is not the profiler sample buffer is used as a ring buffer
Definition switch_defs.h:98
Point Vector2
Definition point.h:429
float Scalar
Definition scalar.h:19
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:55
static std::string NormalizeUniformKey(const std::string &key)
constexpr std::optional< GLenum > ToVertexAttribType(ShaderType type)
size_t length
Definition range.h:15
size_t offset
Definition range.h:14
constexpr bool IsAtLeast(const Version &other) const
Definition version.h:31
std::shared_ptr< const fml::Mapping > data
#define VALIDATION_LOG
Definition validation.h:91