Flutter Engine
The Flutter Engine
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
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
An object that allocates device memory.
Definition allocator.h:22
static DeviceBufferGLES & Cast(DeviceBuffer &base)
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
static const uint8_t buffer[]
GAsyncResult * result
const char * name
Definition fuchsia.cc:50
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
Point Vector2
Definition point.h:320
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)
std::vector< BufferAndUniformSlot > buffers
Definition command.h:75
#define VALIDATION_LOG
Definition validation.h:73