Flutter Impeller
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 <algorithm>
8 #include <cstring>
9 #include <vector>
10 
11 #include "impeller/base/config.h"
17 
18 namespace impeller {
19 
21 
23 
25  const ProcTableGLES& gl,
26  const std::vector<ShaderStageIOSlot>& p_inputs,
27  const std::vector<ShaderStageBufferLayout>& layouts) {
28  std::vector<VertexAttribPointer> vertex_attrib_arrays;
29  for (auto i = 0u; i < p_inputs.size(); i++) {
30  const auto& input = p_inputs[i];
31  const auto& layout = layouts[input.binding];
32  VertexAttribPointer attrib;
33  attrib.index = input.location;
34  // Component counts must be 1, 2, 3 or 4. Do that validation now.
35  if (input.vec_size < 1u || input.vec_size > 4u) {
36  return false;
37  }
38  attrib.size = input.vec_size;
39  auto type = ToVertexAttribType(input.type);
40  if (!type.has_value()) {
41  return false;
42  }
43  attrib.type = type.value();
44  attrib.normalized = GL_FALSE;
45  attrib.offset = input.offset;
46  attrib.stride = layout.stride;
47  vertex_attrib_arrays.emplace_back(attrib);
48  }
49  vertex_attrib_arrays_ = std::move(vertex_attrib_arrays);
50  return true;
51 }
52 
53 static std::string NormalizeUniformKey(const std::string& key) {
54  std::string result;
55  result.reserve(key.length());
56  for (char ch : key) {
57  if (ch != '_') {
58  result.push_back(toupper(ch));
59  }
60  }
61  return result;
62 }
63 
64 static std::string CreateUniformMemberKey(const std::string& struct_name,
65  const std::string& member,
66  bool is_array) {
67  std::string result;
68  result.reserve(struct_name.length() + member.length() + (is_array ? 4 : 1));
69  result += struct_name;
70  result += '.';
71  result += member;
72  if (is_array) {
73  result += "[0]";
74  }
75  return NormalizeUniformKey(result);
76 }
77 
78 static std::string CreateUniformMemberKey(
79  const std::string& non_struct_member) {
80  return NormalizeUniformKey(non_struct_member);
81 }
82 
84  GLuint program) {
85  if (!gl.IsProgram(program)) {
86  return false;
87  }
88  GLint max_name_size = 0;
89  gl.GetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_name_size);
90 
91  GLint uniform_count = 0;
92  gl.GetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniform_count);
93  for (GLint i = 0; i < uniform_count; i++) {
94  std::vector<GLchar> name;
95  name.resize(max_name_size);
96  GLsizei written_count = 0u;
97  GLint uniform_var_size = 0u;
98  GLenum uniform_type = GL_FLOAT;
99  // Note: Active uniforms are defined as uniforms that may have an impact on
100  // the output of the shader. Drivers are allowed to (and often do)
101  // optimize out unused uniforms.
102  gl.GetActiveUniform(program, // program
103  i, // index
104  max_name_size, // buffer_size
105  &written_count, // length
106  &uniform_var_size, // size
107  &uniform_type, // type
108  name.data() // name
109  );
110  auto location = gl.GetUniformLocation(program, name.data());
111  if (location == -1) {
112  VALIDATION_LOG << "Could not query the location of an active uniform.";
113  return false;
114  }
115  if (written_count <= 0) {
116  VALIDATION_LOG << "Uniform name could not be read for active uniform.";
117  return false;
118  }
119  uniform_locations_[NormalizeUniformKey(std::string{
120  name.data(), static_cast<size_t>(written_count)})] = location;
121  }
122  return true;
123 }
124 
126  size_t vertex_offset) const {
127  for (const auto& array : vertex_attrib_arrays_) {
128  gl.EnableVertexAttribArray(array.index);
129  gl.VertexAttribPointer(array.index, // index
130  array.size, // size (must be 1, 2, 3, or 4)
131  array.type, // type
132  array.normalized, // normalized
133  array.stride, // stride
134  reinterpret_cast<const GLvoid*>(static_cast<GLsizei>(
135  vertex_offset + array.offset)) // pointer
136  );
137  }
138 
139  return true;
140 }
141 
143  const ProcTableGLES& gl,
144  Allocator& transients_allocator,
145  const Bindings& vertex_bindings,
146  const Bindings& fragment_bindings) const {
147  for (const auto& buffer : vertex_bindings.buffers) {
148  if (!BindUniformBuffer(gl, transients_allocator, buffer.second.view)) {
149  return false;
150  }
151  }
152  for (const auto& buffer : fragment_bindings.buffers) {
153  if (!BindUniformBuffer(gl, transients_allocator, buffer.second.view)) {
154  return false;
155  }
156  }
157 
158  if (!BindTextures(gl, vertex_bindings, ShaderStage::kVertex)) {
159  return false;
160  }
161 
162  if (!BindTextures(gl, fragment_bindings, ShaderStage::kFragment)) {
163  return false;
164  }
165 
166  return true;
167 }
168 
170  for (const auto& array : vertex_attrib_arrays_) {
171  gl.DisableVertexAttribArray(array.index);
172  }
173  return true;
174 }
175 
176 bool BufferBindingsGLES::BindUniformBuffer(const ProcTableGLES& gl,
177  Allocator& transients_allocator,
178  const BufferResource& buffer) const {
179  const auto* metadata = buffer.GetMetadata();
180  auto device_buffer =
181  buffer.resource.buffer->GetDeviceBuffer(transients_allocator);
182  if (!device_buffer) {
183  VALIDATION_LOG << "Device buffer not found.";
184  return false;
185  }
186  const auto& device_buffer_gles = DeviceBufferGLES::Cast(*device_buffer);
187  const uint8_t* buffer_ptr =
188  device_buffer_gles.GetBufferData() + buffer.resource.range.offset;
189 
190  if (metadata->members.empty()) {
191  VALIDATION_LOG << "Uniform buffer had no members. This is currently "
192  "unsupported in the OpenGL ES backend. Use a uniform "
193  "buffer block.";
194  return false;
195  }
196 
197  for (const auto& member : metadata->members) {
198  if (member.type == ShaderType::kVoid) {
199  // Void types are used for padding. We are obviously not going to find
200  // mappings for these. Keep going.
201  continue;
202  }
203 
204  size_t element_count = member.array_elements.value_or(1);
205 
206  const auto member_key =
207  CreateUniformMemberKey(metadata->name, member.name, element_count > 1);
208  const auto location = uniform_locations_.find(member_key);
209  if (location == uniform_locations_.end()) {
210  // The list of uniform locations only contains "active" uniforms that are
211  // not optimized out. So this situation is expected to happen when unused
212  // uniforms are present in the shader.
213  continue;
214  }
215 
216  size_t element_stride = member.byte_length / element_count;
217 
218  auto* buffer_data =
219  reinterpret_cast<const GLfloat*>(buffer_ptr + member.offset);
220 
221  std::vector<uint8_t> array_element_buffer;
222  if (element_count > 1) {
223  // When binding uniform arrays, the elements must be contiguous. Copy the
224  // uniforms to a temp buffer to eliminate any padding needed by the other
225  // backends.
226  array_element_buffer.resize(member.size * element_count);
227  for (size_t element_i = 0; element_i < element_count; element_i++) {
228  std::memcpy(array_element_buffer.data() + element_i * member.size,
229  reinterpret_cast<const char*>(buffer_data) +
230  element_i * element_stride,
231  member.size);
232  }
233  buffer_data =
234  reinterpret_cast<const GLfloat*>(array_element_buffer.data());
235  }
236 
237  switch (member.type) {
238  case ShaderType::kFloat:
239  switch (member.size) {
240  case sizeof(Matrix):
241  gl.UniformMatrix4fv(location->second, // location
242  element_count, // count
243  GL_FALSE, // normalize
244  buffer_data // data
245  );
246  continue;
247  case sizeof(Vector4):
248  gl.Uniform4fv(location->second, // location
249  element_count, // count
250  buffer_data // data
251  );
252  continue;
253  case sizeof(Vector3):
254  gl.Uniform3fv(location->second, // location
255  element_count, // count
256  buffer_data // data
257  );
258  continue;
259  case sizeof(Vector2):
260  gl.Uniform2fv(location->second, // location
261  element_count, // count
262  buffer_data // data
263  );
264  continue;
265  case sizeof(Scalar):
266  gl.Uniform1fv(location->second, // location
267  element_count, // count
268  buffer_data // data
269  );
270  continue;
271  }
283  case ShaderType::kVoid:
285  case ShaderType::kDouble:
286  case ShaderType::kStruct:
287  case ShaderType::kImage:
290  VALIDATION_LOG << "Could not bind uniform buffer data for key: "
291  << member_key;
292  return false;
293  }
294  }
295  return true;
296 }
297 
298 bool BufferBindingsGLES::BindTextures(const ProcTableGLES& gl,
299  const Bindings& bindings,
300  ShaderStage stage) const {
301  size_t active_index = 0;
302  for (const auto& data : bindings.sampled_images) {
303  const auto& texture_gles = TextureGLES::Cast(*data.second.texture.resource);
304  if (data.second.texture.GetMetadata() == nullptr) {
305  VALIDATION_LOG << "No metadata found for texture binding.";
306  return false;
307  }
308 
309  const auto uniform_key =
310  CreateUniformMemberKey(data.second.texture.GetMetadata()->name);
311  auto uniform = uniform_locations_.find(uniform_key);
312  if (uniform == uniform_locations_.end()) {
313  VALIDATION_LOG << "Could not find uniform for key: " << uniform_key;
314  return false;
315  }
316 
317  //--------------------------------------------------------------------------
318  /// Set the active texture unit.
319  ///
320  if (active_index >= gl.GetCapabilities()->GetMaxTextureUnits(stage)) {
321  VALIDATION_LOG << "Texture units specified exceed the capabilities for "
322  "this shader stage.";
323  return false;
324  }
325  gl.ActiveTexture(GL_TEXTURE0 + active_index);
326 
327  //--------------------------------------------------------------------------
328  /// Bind the texture.
329  ///
330  if (!texture_gles.Bind()) {
331  return false;
332  }
333 
334  //--------------------------------------------------------------------------
335  /// If there is a sampler for the texture at the same index, configure the
336  /// bound texture using that sampler.
337  ///
338  const auto& sampler_gles = SamplerGLES::Cast(*data.second.sampler.resource);
339  if (!sampler_gles.ConfigureBoundTexture(texture_gles, gl)) {
340  return false;
341  }
342 
343  //--------------------------------------------------------------------------
344  /// Set the texture uniform location.
345  ///
346  gl.Uniform1i(uniform->second, active_index);
347 
348  //--------------------------------------------------------------------------
349  /// Bump up the active index at binding.
350  ///
351  active_index++;
352  }
353  return true;
354 }
355 
356 } // namespace impeller
impeller::BufferBindingsGLES::ReadUniformsBindings
bool ReadUniformsBindings(const ProcTableGLES &gl, GLuint program)
Definition: buffer_bindings_gles.cc:83
impeller::ShaderType::kAtomicCounter
@ kAtomicCounter
impeller::Resource::resource
ResourceType resource
Definition: command.h:37
impeller::Scalar
float Scalar
Definition: scalar.h:15
impeller::ShaderType::kDouble
@ kDouble
impeller::BufferBindingsGLES::RegisterVertexStageInput
bool RegisterVertexStageInput(const ProcTableGLES &gl, const std::vector< ShaderStageIOSlot > &inputs, const std::vector< ShaderStageBufferLayout > &layouts)
Definition: buffer_bindings_gles.cc:24
impeller::BufferBindingsGLES::BufferBindingsGLES
BufferBindingsGLES()
impeller::Range::offset
size_t offset
Definition: range.h:14
impeller::ShaderType::kSignedInt64
@ kSignedInt64
texture_gles.h
impeller::Vector2
Point Vector2
Definition: point.h:310
impeller::ShaderType::kImage
@ kImage
impeller::ShaderStage
ShaderStage
Definition: shader_types.h:20
impeller::ShaderType::kVoid
@ kVoid
impeller::Bindings::buffers
std::map< size_t, BufferAndUniformSlot > buffers
Definition: command.h:79
impeller::ShaderType::kSignedByte
@ kSignedByte
impeller::BufferView::range
Range range
Definition: buffer_view.h:16
validation.h
sampler_gles.h
impeller::ShaderType::kUnsignedShort
@ kUnsignedShort
impeller::NormalizeUniformKey
static std::string NormalizeUniformKey(const std::string &key)
Definition: buffer_bindings_gles.cc:53
impeller::Resource< BufferView >
impeller::ShaderType::kUnsignedInt64
@ kUnsignedInt64
impeller::ShaderType::kUnsignedByte
@ kUnsignedByte
impeller::ShaderType::kFloat
@ kFloat
device_buffer_gles.h
impeller::BufferBindingsGLES::UnbindVertexAttributes
bool UnbindVertexAttributes(const ProcTableGLES &gl) const
Definition: buffer_bindings_gles.cc:169
impeller::ShaderType::kBoolean
@ kBoolean
impeller::ShaderType::kSampler
@ kSampler
impeller::BufferView::buffer
std::shared_ptr< const Buffer > buffer
Definition: buffer_view.h:14
impeller::ShaderType::kSampledImage
@ kSampledImage
impeller::Allocator
An object that allocates device memory.
Definition: allocator.h:25
impeller::ProcTableGLES
Definition: proc_table_gles.h:188
impeller::ShaderStage::kFragment
@ kFragment
impeller::ToVertexAttribType
constexpr std::optional< GLenum > ToVertexAttribType(ShaderType type)
Definition: formats_gles.h:138
impeller::ShaderType::kUnsignedInt
@ kUnsignedInt
formats_gles.h
buffer_bindings_gles.h
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:60
impeller::ShaderType::kStruct
@ kStruct
impeller::ShaderType::kSignedShort
@ kSignedShort
impeller::ShaderType::kHalfFloat
@ kHalfFloat
impeller::ShaderType::kSignedInt
@ kSignedInt
impeller::ShaderStage::kVertex
@ kVertex
impeller::BufferBindingsGLES::BindVertexAttributes
bool BindVertexAttributes(const ProcTableGLES &gl, size_t vertex_offset) const
Definition: buffer_bindings_gles.cc:125
impeller::BackendCast< DeviceBufferGLES, DeviceBuffer >::Cast
static DeviceBufferGLES & Cast(DeviceBuffer &base)
Definition: backend_cast.h:14
impeller::ShaderType::kUnknown
@ kUnknown
impeller::BufferBindingsGLES::~BufferBindingsGLES
~BufferBindingsGLES()
impeller::Resource::GetMetadata
const ShaderMetadata * GetMetadata() const
Definition: command.h:48
config.h
impeller
Definition: aiks_context.cc:10
impeller::CreateUniformMemberKey
static std::string CreateUniformMemberKey(const std::string &struct_name, const std::string &member, bool is_array)
Definition: buffer_bindings_gles.cc:64
impeller::Bindings
Definition: command.h:77
impeller::BufferBindingsGLES::BindUniformData
bool BindUniformData(const ProcTableGLES &gl, Allocator &transients_allocator, const Bindings &vertex_bindings, const Bindings &fragment_bindings) const
Definition: buffer_bindings_gles.cc:142